Base solution for your next web application
Open Closed

Change history of some domain properties. #1394


User avatar
0
eggersa created

To allow for statistics on an entity class I need to somehow log changes with the current date of a small set of properties for that specific entity. However, since there are dozens of ways to do this (technically) I was wondering on how to properly do this?

  • The simplest way I could think of would be to have a collection with the logs inside the entity class and simply add a new log entry inside the setter of the property that needs to be logged. But this seems messy in many ways.
  • Another idea is to create a custom repository (by inheriting the generic repository) and log changes of the properties in the insert or update methods respectively. But that adds logic to the repository which is out of its responsibility.
  • Further ideas involve the event bus or a custom interceptor. Maybe the interceptor is the way to go?

6 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    We are planning to do this as well but we haven't think about it so much <a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/issues/447">https://github.com/aspnetboilerplate/as ... issues/447</a>.

    EventBus might be used here with EntityUpdatingEventData<> generic event data class, but you need to get the origianal version in that case from database.

  • User Avatar
    0
    hikalkan created
    Support Team

    You can also override SaveChanges and SaveChangesAsync methods of your dbcontext, get changed entities and create logs. We are doing it to trigger events and set audit properties for changed entities (<a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.EntityFramework/EntityFramework/AbpDbContext.cs#L180">https://github.com/aspnetboilerplate/as ... xt.cs#L180</a>) As better, just override ApplyAbpConcepts (<a class="postlink" href="https://github.com/aspnetboilerplate/aspnetboilerplate/blob/dev/src/Abp.EntityFramework/EntityFramework/AbpDbContext.cs#L208">https://github.com/aspnetboilerplate/as ... xt.cs#L208</a>) method.

    I believe there should be single EntityLog/EntityChanges entity/class if you just want to log changes.

  • User Avatar
    0
    eggersa created

    Thank you for the answers. I prefer the way with the event bus since it seems business related and I think we both agree that business rules have no "business" in the orm layer. However, inside the HandleEvent method it seems difficult to get the original object:

    public class ShootingStatisticsHandler : IEventHandler<EntityUpdatingEventData<Shooting>>, ITransientDependency
        {
            private readonly IRepository<Shooting> shootingRepository;
    
            public ShootingStatisticsHandler(IRepository<Shooting> shootingRepository)
            {
                this.shootingRepository = shootingRepository;
            }
    
            public async void HandleEvent(EntityUpdatingEventData<Shooting> eventData)
            {
                Shooting original = await shootingRepository.FirstOrDefaultAsync(eventData.Entity.Id);
                // ...
            }
        }
    

    And the update method in the application layer looks like this:

    public async Task UpdateShooting(ShootingEditDto input)
            {
                var shooting = await shootingRepository.FirstOrDefaultAsync(input.Id.Value);
                input.MapTo(shooting);
            }
    

    For some reason, the repository in the event handler returns the already changed object. Is there some caching going on behind I am not aware about?

  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    It seems related to business, but it's only possible by the help of infrastructure (Entity Framework). So, go with overriding ApplyAbpConcepts, that's easier and I think it does not have problems with DDD.

    EntityUpdatingEventData gets changed entity and does not provide the original entity which is very hard since it can have relations and they might be changed etc.. EF also provides it property by property.

    Have a nice day.

  • User Avatar
    0
    maharatha created

    Hi Hilkan -

    I had a requirement to track changes to few property of a Entity which I am able to do overriding ApplyABpConcepts.

    I am filtering the tracking by filtering the Entity name, but the problem is when I am trying to insert a record based on the calculation from previous and new values and try to insert into another table then again the ApplyAbpConcepts is called which now has the entity which I am tracking and the new entity to which I am inserting a record. As a result I am getting into an infinite loop.

    Is there a way where i can stop tracking for an entity ?

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    You can try to change state of Entity after finishing your job with it like this,

    dbContext.Entry(entity).State = EntityState.Detached;
    

    I dont know your case very well but overriding SaveChanges might be a better choice as Halil said.