- ABP Framework version: 4.4.2
- UI type: Angular
- DB provider: EF Core
- Tiered (MVC) or Identity Server Separated (Angular): no
We have a situation where we should attatch some extra information to our entites. For example: EntityX has some properties and in addition Tenant1 needs to see extra property "Xyx" and it's value in UI. Tenant2 also needs extra property for EntityX but with different name "Abc" and possibly different value type. These extra properties cannot be determined at build time. At our old solution we just had extra columns for some database tables and meaning of the value was taken care of in customer guidance. I'm looking for more elegant solution than that and was wondering if the Extra Properties -model could provide the solution?
5 Answer(s)
-
0
By default, ABP saves all custom properties in the
ExtraProperties
field as a singleJSON
, object. If you prefer to create a tablespace for a custom property, you can configure it as follows in theEntityFrameworkCore
project in the classMyProjectNameEfCoreEntityExtensionMappings.cs
.ObjectExtensionManager.Instance .MapEfCoreProperty<IdentityUser, string>( "SocialSecurityNumber", (entityBuilder, propertyBuilder) => { propertyBuilder.HasMaxLength(64).IsRequired().HasDefaultValue(""); } );
However when you do this, you cannot change the value type and name as the property will be kept as a separate column in the database table, so you should use the default.
As mentioned in this document, you can save the data with the name and value type you want in the
ExtraProperties
column by usingSetProperty
. -
0
Hello, I think the JSON-field will suffice. But the problem isn't that can we map it to another table or not. The problem is that the meaning and value types change will change accross different tenants. For example: Tenant1 needs an additional property "SocialSecurityNumber" which is of type string but Tenant2 doen't care about that information. It needs an additional property "PersonLength" of type integer. We cannot know in advance what additional information each tenant needs, so the properties cannot be defined in advance like in the SetProperty-example. The JSON value would be created dynamically to the database by an external system (an integrator).
-
0
I understand the problem, I just gave the example code in my previous answer to emphasize that you should use ABP's default behavior, not the
MapEfCoreProperty
method.As you said, JSON-field will suffice. So just use the
ExtraProperties
field.When you save a few values in the
ExtraProperties
field and open the database, can you see that value in theExtraProperties
field? For example, can't you currently saveSocialSecurityNumber
as123
forTenant1
andPersonLength
as99
forTenant2
in theExtraProperties
field in the database?If you can't save it, please share the sample code or I can share the sample code if you want 😊
-
0
I have no doupt that saving isn't a problem with this. To be clear, I haven't tried any solution yet, hence the "Design Question". However all the examples I have seen define the extraproperty name staticly and I'm trying to figure out if this king dynamic definition would work as well. If you have some sample code, I will gladly take a look at it :)
-
0
As an example, I am sharing the code of the sample I wrote quickly.
I created a folder named
IdentityUsers
under theMvcPro.Application
project and into created the class namedMyIdentityUserAppService
as follows:[Dependency(ReplaceServices = true)] [ExposeServices(typeof(IIdentityUserAppService), typeof(IdentityUserAppService), typeof(MyIdentityUserAppService))] public class MyIdentityUserAppService : IdentityUserAppService, IIdentityUserAppService { public MyIdentityUserAppService( IdentityUserManager userManager, IIdentityUserRepository userRepository, IIdentityRoleRepository roleRepository, IOrganizationUnitRepository organizationUnitRepository, IIdentityClaimTypeRepository identityClaimTypeRepository, IdentityProTwoFactorManager identityProTwoFactorManager, IOptions<IdentityOptions> identityOptions, IDistributedEventBus distributedEventBus) : base( userManager, userRepository, roleRepository, organizationUnitRepository, identityClaimTypeRepository, identityProTwoFactorManager, identityOptions, distributedEventBus) { } public override async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input) { var identityUserDto = await base.CreateAsync(input); var user = await base.UserRepository.GetAsync(identityUserDto.Id); if (CurrentTenant.Id == null) { user.SetProperty("SocialSecurityNumber", "My SocialSecurityNumber is 123"); } else { user.SetProperty("PersonLength", 99); } await base.UserRepository.UpdateAsync(user); return identityUserDto; } }
As you can see from the code, I set two completely different properties that vary depending on the tenant if there is or not.
While testing the code, logging in with the admin user, clicking Identity Management from the menu, then Users, creating a new user. Then create a new tenant and login with the tenant's admin user, then create a user again.
In the picture below you can see that it is saved in the database.
You can apply similar logic according to your needs.
I'm closing this question because I think it's clear enough. If you run into a problem with this, feel free to open it.