开发者

EntityFramework: Update single field with detached entity

Unlike normal, I have code that actually works, but I'm wondering if it's the only (or best approach).

The basic Idea is I have an existing application that's handmade data layer is being ported to Entity Framework. As a compromise to minimize code changes, I'm working with existing methods, which tend to take a more disconnected approach. For example I have a lot of things like this:

UpdateNote(int noteId, string note)

I seem to have a method that works for this type of update without requiring a re-fetch:

var context = new MyEntities();
context.Configuration.ValidateOnSaveEnabled = false;
var note = new Model.Note{ Id = noteId, Note = ""};
context.Notes.Attach(note);
note.Note = "Some Note";
context.SaveChanges();

It's a little ugly (though concise enough), so I would like to know if there is there a better approach to use with EF? Any downsides to this method, other than loosing built-in validation?

This is a pattern that will be used all over my app开发者_如何转开发.


The following extension method for DbContext is an approach which would avoid to initialize your entities with some values different to the values you want to change it to.

public static class EFExtensions
{
    public static void MarkAsModified(this DbContext context, object entity,
        params string[] properties)
    {
        foreach (var property in properties)
            context.Entry(entity).Property(property).IsModified = true;
    }
}

You could then use it this way:

var context = new MyEntities();
context.Configuration.ValidateOnSaveEnabled = false;

var note = new Model.Note { Id = noteId }; // only key properties required to set

note.Note = "Some Note";
note.SomeOtherProperty = 1234;
note.AndAnotherProperty = "XYZ";

context.Notes.Attach(note);
context.MarkAsModified(note, "Note", "SomeOtherProperty" , "AndAnotherProperty");

context.SaveChanges();

Note: This only works for scalar properties, not navigation properties.

Besides validation I could imagine that this approach is problematic for a proper concurrency checking.

Edit

According to @Adam Tuliper's comment below concurrency is likely not a problem because the concurrency check is skipped when an entity is attached manually to the context (without reading it from the database) and marked as modified to send an UPDATE command to the database. It just overwrites the lastest version in the DB. Thanks to Adam for pointing this out!


See the following code I use to easily attach a disconnected object back to the graph, assuming we're now going to save it.


public static class EntityFrameworkExtensions
{
    /// <summary>
    /// This class allows you to attach an entity.
    /// For instance, a controller method Edit(Customer customer)
    /// using ctx.AttachAsModified(customer); 
    /// ctx.SaveChanges();
    /// allows you to easily reattach this item for udpating.
    /// Credit goes to: http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx
    /// </summary>
    public static void AttachAsModified<T>(this ObjectSet<T> objectSet, T entity) where T : class
    {
        objectSet.Attach(entity);
        objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }

    /// <summary>
    /// This marks an item for deletion, but does not currently mark child objects (relationships).
    /// For those cases you must query the object, include the relationships, and then delete.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="objectSet"></param>
    /// <param name="entity"></param>
    public static void AttachAsDeleted<T>(this ObjectSet<T> objectSet, T entity) where T : class
    {
        objectSet.Attach(entity);
        objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Deleted);
    }

    public static void AttachAllAsModified<T>(this ObjectSet<T> objectSet, IEnumerable<T> entities) where T : class
    {
        foreach (var item in entities)
        {
            objectSet.Attach(item);
            objectSet.Context.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜