7

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

1 Answer 1

5

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;
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thx, that solution works for me. BTW params Expression<Func<T, object>>[] updatedProperties can be easily changed to params String[] updatedPropertiesNames, because dbEntityEntry.Property() has overload with String parameter. Moreover, even if I update some property value and forget to add that property name to updatedPropertiesNames - block of code after else works like a charm (enumerating all values is, of course, much slower - but it's a good safeguard).
dbEntityEntry.Property(property).IsModified = true; This line gives me an error while compiling in EF Core 5.0. Looks like EF Core has only .Properties (string propName) defined

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.