Nick N.
Nick N.

Reputation: 13559

Generic check if something has changed with entity framework and repository pattern

My update method will always update since I have to set the LastModified date. I was wondering if there is a way to dynamically check if some values have changed.

My state objects look like this:

public partial class Action : IEntity
{
    public long Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public System.DateTime Created { get; set; }
    public System.DateTime LastModified { get; set; }
    public Nullable<System.DateTime> Deleted { get; set; }
}

The interface I use looks like this:

public interface IEntity
{
    long Id { get; set; }        
    DateTime Created { get; set; }
    DateTime LastModified { get; set; }
    DateTime? Deleted { get; set; }       
}

My update method looks like this (The changes are saved later):

    public virtual void Update(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        var attachedEntity = DbSet.Find(entity.Id);

        if (attachedEntity != null)
        {
            var attachedEntry = DbContext.Entry(attachedEntity);

            entity.Created = attachedEntity.Created;
            entity.LastModified = DateTime.Now;

            attachedEntry.CurrentValues.SetValues(entity);
        }
        else
        {
            dbEntityEntry.State = EntityState.Modified;
            entity.LastModified = DateTime.Now;
        }
    }

So it will actually perform a generic update for every object that is passed as T with the the IEntity Interface. However it performs the update every single call to this method because the LastModified value is changed. Resulting in many update queries like these:

exec sp_executesql N'update [dbo].[BiztalkEntity]
set [LastModified] = @0
where ([Id] = @1)
',N'@0 datetime2(7),@1 bigint',@0='2013-05-17 11:22:52.4183349',@1=10007

Could you tell me how to prevent the query being executed every single time?

Upvotes: 2

Views: 7923

Answers (1)

qujck
qujck

Reputation: 14580

I suggest you delay the setting of LastModified and let Entity Framework give you all the entities that have been changed just prior to the changes being sent to the database.

You can override the SaveChanges() method of DbContext

public class MyContext : DbContext
{
    public override int SaveChanges()
    {
        //you may need this line depending on your exact configuration
        //ChangeTracker.DetectChanges();
        foreach (DbEntityEntry o in GetChangedEntries())
        {
            IEntity entity = o.Entity as IEntity;
            entity.LastModified = DateTime.Now;
        }
        return base.SaveChanges();
    }

    private IEnumerable<DbEntityEntry> GetChangedEntries()
    {
        return new List<DbEntityEntry>(
            from e in ChangeTracker.Entries()
            where e.State != System.Data.EntityState.Unchanged
            select e);
    }
}

Upvotes: 6

Related Questions