Question

I'm trying to figure out how to mark specific properties of a detached entity as modified. If I do the following, it will mark all properties modified and the generated sql will update all columns.

/// <summary>
/// Sets the entity in the modified state.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entity">The entity.</param>
void IDbContext.Modified<T>(T entity)
{
    DbEntityEntry<T> entry = Entry(entity);
    if (entry.State == EntityState.Modified)
    {
        // if the state is already Modified we don't need to do anything else
        return;
    }

    if (entry.State == EntityState.Detached)
    {
        Set<T>().Attach(entity);

        //TODO: set specific properties modified instead of the the whole object.
        entry.State = EntityState.Modified;
    }
}

How do I set only changed properties as Modified?

I'm trying to use this in a class that implements DbContext that will be used by a generic repository. The goal is to automagically determine which properties have changed compared to the database values and then set those changed properties states to Modified. In my current implementation, the Modified method has no knowledge of the entity type, so I can't simply retrieve it with context.Set<T>.Find(key).

I suppose I could add an overload that accepts an originalEntity parameter, but I'd rather not if possible.

void IDbContext.Modified<T>(T entity, T originalEntity)
{
    DbEntityEntry<T> entry = Entry(entity);
    if (entry.State == EntityState.Modified)
    {
        // if the state is already Modified we don't need to do anything else
        return;
    }

    if (entry.State == EntityState.Detached)
    {
        Set<T>().Attach(entity);

        entry.OriginalValues.SetValues(originalEntity);
    }
}
Was it helpful?

Solution

You must do it for each property manually by calling:

DbEntityEntry<T> entry = context.Entry(entity);
if (entry.State == EntityState.Detached)
{
    context.Set<T>().Attach(entity);
    entry.Property(e => e.SomeProperty).IsModified = true;
    // TODO other properties
}

Edit:

Former example suppose that you don't want to reload the entity from the database and in such case you must know which properties are changed - it is up to you to implement it.

If you are happy with additional query to database you can use this:

var persistedEntity = context.Set<T>.Find(key);
var entry = context.Entry(persistedEntity);
entry.CurrentValues.SetValues(entity);

Edit2:

Setting original values should be reverse operation (but I have never tried this):

var persistedEntity = context.Set<T>.Find(key);
context.Entry(persistedEntity).State = EntityState.Detached;

var entry = context.Entry(entity);
context.Set<T>.Attach(entity);
// I'm not sure if you have to change the state of the entity
entry.OriginalValues.SetValues(persistedEntity);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top