Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto update only changed properties for an entity via EntityFramework

Let's say we have a MyDbContext having DbSet<MyEntity> in it. I'm trying to implement the following scenario (as I found out it is called disconnected scenario or disconnected mode):

  1. I obtain List<MyEntity> from database (it can be simply all records via DbContext.MyEntities.ToList() or records by some filter condition - it doesn't matter).
  2. Then those entities are passed to some UI where user can change properties. His behaviour is unpredictable: he can change every property of every entity or he can change only one property of a single entity (he even can perform no changes at all).
  3. After that I need to pass the updates to database.

To implement that scenario I've found for me two possible solutions:

1) Keep connection open during the whole scenario. So it will work like this:

MyDbContext.Database.Connection.Open();
List<MyEntity> EntitiesList = MyDbContext.MyEntities.ToList();

//passing EntitiesList to the UI, where user can change them
EntitiesList[0].SomeStringProperty = "123";
//change some other properties here

//saving changes to database some time later
MyDbContext.SaveGhanges();
MyDbContext.Database.Connection.Close();

But in this solution database connection persists open too long. It shouldn't be open when UI is working (because user can change entities during several hours for example).

2) Close connection after obtaining List<MyEntity> and open connection again when passing updates to database. So it will work like this:

MyDbContext.Database.Connection.Open();
List<MyEntity> EntitiesList = MyDbContext.MyEntities.ToList();
MyDbContext.Database.Connection.Close();

//passing EntitiesList to the UI, where user can change them
EntitiesList[0].SomeStringProperty = "123";
//change some other properties here

//saving changes to database some time later
MyDbContext.Database.Connection.Open();
foreach(var entity in EntitiesList)
{
    //Attach updated entity and make context know that it is modified
    MyDbContext.MyEntities.Attach(entity);
    MyDbContext.MyEntities(entity).State = EntityState.Modified;
}
MyDbContext.SaveGhanges();
MyDbContext.Database.Connection.Close();

But in this solution I think that absolutely all properties of all entites were modified. It results in huge database update overhead.

Another choice will be to write MyEntityWrapper class which will track all changes performed by user and will know which properties needs to be updated. So I can change my code above to this one:

foreach(var entity in EntitiesList)
{
    //Attach updated entity and make context know which properties are modified
    MyDbContext.MyEntities.Attach(entity);
    MyDbContext.Entry(entity).Property(e => e.SomeStringProperty).IsModified = true;
    //mark other changed properties
}

So - is there some more elegant solution, can I update only changed properties without writing MyEntityWrapper class? Can I simply tell DbContext: "here is some List<MyEntity> - take it, determine which properties differs from that values in a database and update those values"?

BTW. If it matters - I'm working with SQLite database via Devart dotConnect for SQLite + EntityFramework 6.0.1

like image 444
bairog Avatar asked Jul 25 '17 05:07

bairog


People also ask

How do I update an existing record in Entity Framework?

We can update records either in connected or disconnected scenarios. In the connected Scenario, we open the context, query for the entity, edit it, and call the SaveChanges method. In the Disconnected scenario, we already have the entity with use. Hence all we need to is to attach/add it to the context.

How do I force Entity Framework to always get updated data from the database?

You just need myContext. Entry(myEntity). Reload(); where myContext is the variable for the DbContext.


1 Answers

Please have a look on below code, I think it may help you (Found out on Google )

public virtual void Update(T entity, params Expression<Func<T, object>>[] updatedProperties)
{
    //Ensure only modified fields are updated.
    var dbEntityEntry = DbContext.Entry(entity);
    if (updatedProperties.Any())
    {
        //update explicitly mentioned properties
        foreach (var property in updatedProperties)
        {
            dbEntityEntry.Property(property).IsModified = true;
        }
    }
    else{
        //no items mentioned, so find out the updated entries
        foreach (var property in dbEntityEntry.OriginalValues.PropertyNames)
        {
            var original = dbEntityEntry.OriginalValues.GetValue<object>(property);
            var current = dbEntityEntry.CurrentValues.GetValue<object>(property);
            if (original != null && !original.Equals(current))
                dbEntityEntry.Property(property).IsModified = true;
        }
    }
}
like image 124
OnDoubt Avatar answered Oct 04 '22 21:10

OnDoubt