Customizing the Application Modules: Extending Entities
Extra properties is a way of storing some additional data on an entity without changing it. The entity should implement the interface to allow it. All the aggregate root entities defined in the pre-built modules implement the IHasExtraProperties
interface, so you can store extra properties on these objects.
Example:
This approach is very easy to use and available out of the box. No extra code needed. You can store more than one property at the same time by using different property names (like Title
here).
Extra properties are stored as a single JSON
formatted string value in the database for the EF Core. For MongoDB, they are stored as separate fields of the document.
See the for more about the extra properties system.
As mentioned above, all extra properties of an entity are stored as a single JSON object in the database table. This is not so natural especially when you want to;
- Write SQL or LINQ using the extra property (search table by the property value, for example).
- Creating your own entity maps to the same table, but defines an extra property as a regular property in the entity (see the EF Core migration document for more).
Assume that you want to add a SocialSecurityNumber
to the IdentityUser
entity of the . You can use the ObjectExtensionManager
:
- You provide the
IdentityUser
as the entity name, as the type of the new property,SocialSecurityNumber
as the property name (also, the field name in the database table). - You also need to provide an action that defines the database mapping properties using the EF Core Fluent API.
Once you define an entity extension, you then need to use the standard and Update-Database commands of the EF Core to create a code first migration class and update your database.
You can then use the same extra properties system defined in the previous section to manipulate the property over the entity.
Another approach can be creating your own entity mapped to the same database table (or collection for a MongoDB database).
AppUser
entity in the already implements this approach. EF Core Migrations document describes how to implement it and manage EF Core database migrations in such a case. It is also possible for MongoDB, while this time you won’t deal with the database migration problems.
Mapping your entity to an existing table of a depended module has a few disadvantages;
- You deal with the database migration structure for EF Core. While it is possible, you should extra care about the migration code especially when you want to add relations between entities.
- Your application database and the module database will be the same physical database. Normally, a module database can be separated if needed, but using the same table restricts it.
In this case, you need to deal with the synchronization problems, especially if you want to duplicate some properties/fields of the related entity. There are a few solutions;
- If you are building a monolithic application (or managing your entity and the related module entity within the same process), you can use the to listen changes.
Once you handle the event, you can update your own entity in your own database.
Local Event Bus system is a way to publish and subscribe to events occurring in the same application.
Assume that you want to get informed when a IdentityUser
entity changes (created, updated or deleted). You can create a class that implements the ILocalEventHandler<EntityChangedEventData<IdentityUser>>
interface.
EntityChangedEventData<T>
covers create, update and delete events for the given entity. If you need, you can subscribe to create, update and delete events individually (in the same class or different classes).- This code will be executed out of the local transaction, because it listens the event. You can subscribe to the
EntityChangingEventData<T>
to perform your event handler in the same local (in-process) transaction if the current is transactional.
Subscribing to Distributed Events
system is a way to publish an event in one application and receive the event in the same or different application running on the same or different server.
Assume that you want to get informed when a IdentityUser
entity created, updated or deleted. You can create a class like below:
- It implements multiple
IDistributedEventHandler
interfaces: Created, Updated and Deleted. Because, the distributed event bus system publishes events individually. There is no “Changed” event like the local event bus. - It subscribes to
EntityEto
, which is a generic event class that is automatically published for all type of entities by the ABP framework. This is why it checks the entity type (checking the entity type as string since we assume that there is no type safe reference to theIdentityUser
entity).
- This handler is executed only when a new user has been created.