Howto only updates changed properties for an entity via EntityFramework
Let's say we have a MyDbContext
with DbSet<MyEntity>
in it. I am trying to implement the following scenario (as I found out it is called disabled script or disabled mode):
- I am getting
List<MyEntity>
from the database (it could just be all records throughDbContext.MyEntities.ToList()
or records by some filter condition - it doesn't matter). - These objects are then passed to some interface where the user can change properties. Its behavior is unpredictable: it can change every property of every entity, or it can change only one property of one object (it can't even make any changes at all).
- After that I need to push the updates to the database.
To implement this scenario, I found two possible solutions for me:
1) Keep the connection open throughout the entire scenario. Therefore 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, the database connection remains open for too long. It shouldn't be open when the UI is running (because the user can modify objects for hours, for example).
2) Close the connection after receiving List<MyEntity>
and open the connection again when pushing updates to the database. So this will work for example:
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 decision, I believe that absolutely all properties of all entites have been changed. This leads to a huge overhead for updating the database.
Another option would be to write a class MyEntityWrapper
that will track all changes made by the user and know which properties need 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 an even more elegant solution, can I update changed properties without writing a class MyEntityWrapper
? Can I just tell the DbContext "here are some List<MyEntity>
- take it, determine which properties differ from these values โโin the database, and update those values"?
BTW. If it matters - I am working with a SQLite database via Devart dotConnect for SQLite + EntityFramework 6.0.1
source to share
Please see below code, I think it can help you (found 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;
}
}
}
source to share