3

At the moment to check for changes with my entity framework object, I check in the database and I go through each object and compare the properties with the updated, if they are updated then my date modified will be updated as well.

I find that it's getting very lengthy in code and was wondering if there's a cleaner way to check for changes using entity framework. I was thinking maybe using deepcopy with a object comparison and compare something like below. But I would have to set each of my tables to be serialized and I don't know if that's a good thing.

if (Equals(oldentity, newentity))
{
    newentity.ModifiedDate = DateTime.Now
}

My current method of tracking changes

if (oldentity.firstname != newentity.firstname || oldentity.lastname != newentity.lastname)
{
    newentity.ModifiedDate = DateTime.Now
}

The if statement is a snippet, my entity has many properties so it gets lengthy...

ozz
  • 5,098
  • 1
  • 50
  • 73
Master
  • 2,038
  • 2
  • 27
  • 77
  • Shouldn't the modified date always be updated any time the entity is persisted, regardless of what values changed? – David May 28 '15 at 14:13
  • Do you use Entity Framework ? If so, `EntityState` should tell you if an entity has been modified, if not then I'd use reflection to loop through all properties and compare. – Francis Ducharme May 28 '15 at 14:13
  • You can look at this answer how to [check in a generic way](http://stackoverflow.com/a/29995396/3790486) all properties of an entity. – adricadar May 28 '15 at 14:14
  • Hi @FrancisDucharme I am using entity framework but I also have a layer of UnitOfWork repository pattern ontop of it. – Master May 28 '15 at 14:15
  • @Master Sorry, not familiar with UoW concept but I believe you should still be able to track changes with the context (`newentity.EntityState`) – Francis Ducharme May 28 '15 at 14:17

3 Answers3

1

You can give your entity an interface with CreatedDate and ModifiedDate properties:

public interface ITrackedEntity
{
    DateTime CreatedDate    { get; set; }
    DateTime ModifiedDate   { get; set; }
}

Then override SaveChanges and SaveChangesAsync in the DBContext to handle updating the properties for added and modified entities automatically:

public override int SaveChanges()
{
    this.UpdateTrackedEntities();
    return base.SaveChanges();
}

public override async Task<int> SaveChangesAsync()
{
    this.UpdateTrackedEntities();
    return await base.SaveChangesAsync();
}

private void UpdateTrackedEntities()
{
    var entities = ChangeTracker.Entries().Where(x => x.Entity is ITrackedEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));

    foreach (var entity in entities)
    {
        if (entity.State == EntityState.Added)
        {
            ((ITrackedEntity)entity.Entity).CreatedDate = DateTime.UtcNow;
        }

        ((ITrackedEntity)entity.Entity).ModifiedDate = DateTime.UtcNow;
    }
}

Makes things a lot simpler.

David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • The idea behind this can be found [here](http://stackoverflow.com/a/16557167/188246). – David Sherret May 28 '15 at 14:29
  • Hi David, I feel this would update modified anytime entity is persisted. I'm trying to have it update only when properties have been updated. Unless I'm understanding the code wrong? – Master May 28 '15 at 14:34
  • @Master I think if the entity hasn't been modified it will have a state of `EntityState.Unchanged`, but I haven't run a test to check for sure. The check `x.State == EntityState.Added || x.State == EntityState.Modified` should only update added or modified entities. – David Sherret May 28 '15 at 14:39
  • Sweet jesus it worked! Thank you. It definitely worked how I wanted to. – Master May 28 '15 at 15:18
  • @Master awesome! I'm glad it helped. – David Sherret May 28 '15 at 15:51
0

You can try something like

public bool HasUnsavedChanges(MyObject oldentity)
{
    return (YourObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Any(x=>x.Id == oldentity.Id));
}
dariogriffo
  • 4,148
  • 3
  • 17
  • 34
0

Entity Framework has a ChangeTracker in DbContext.

I for example have a override of my context's SaveChanges() and it is able to get all the changes made in my entities.

public override int SaveChanges()
{
    ChangeTracker.DetectChanges();
    var addedEntities = ChangeTracker.Entries().Where(x => x.State == EntityState.Added).ToList();
    var modifiedEntities = ChangeTracker.Entries().Where(x => x.State == EntityState.Modified).ToList();
    var deletedEntities = ChangeTracker.Entries().Where(x => x.State == EntityState.Deleted).ToList();

    //Save info generating the ids
    var ret = base.SaveChanges();

    //Generate Logs logic
    ...

    return ret;
}

ChangeTracker also accepts an entity as parameter if you want to check a just a single entity for changes.

More info on ChangeTracker (https://msdn.microsoft.com/en-us/library/system.data.entity.infrastructure.dbchangetracker(v=vs.113).aspx)

Rafael Merlin
  • 2,517
  • 1
  • 25
  • 31