Attaching Modified Entities in EF 4

Lately I've been working with EF 4.0 and finding that many of the new features are catching up with the features previously available in other framework like LINQ to SQL.  One example of this is the ability to easily attach objects (for example, disconnected objects that come in from another tier).  For example, imagine you had a web service where a consumer submitted an object to get saved – you'd want to instantiate a new context, attach the incoming entity, and save the object.  In previous versions of EF, this was not a trivial thing to do.  However, this was always quite easy to do in LINQ to SQL by doing this:

using (var dataContext = new MyDataContext())
{
    dataContext.Contacts.Attach(someEntity, true);
    dataContext.SubmitChanges();
}

Notice the second Boolean parameters of the Attach() method – this instructs the context that the entity should treated "as modified" so that an UPDATE command should be issued for that entity when SubmitChanges() gets called (LINQ to SQL also provides an AttachAll() method for collections).  You can now do the same thing in EF 4 like this (I'm using POCO and Code Only here):

using (var dataContext = new MyDataContext())
{
    dataContext.Contacts.Attach(contact);
    dataContext.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    dataContext.SaveChanges();
}

This is a huge leap forward from previous versions of EF but notice that this actually takes one more line of code than its LINQ to SQL counterpart because an explicit call to the ObjectManager's ChangeObjectState() method must be called. Although this might appear to be a slight inconvenience, it is possible to write a couple of extension methods to simplify this since the ObjectSet's all have a reference to the parent Context:

static class ContextExtensions
{
    public static void AttachAsModified<T>(this ObjectSet<T> objectSet, T entity) where T : class
    {
        objectSet.Attach(entity);
        objectSet.Context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
    }
 
    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);
        }
    }
}

This allows you to now save like this:

using (var dataContext = new MyDataContext())
{
    dataContext.Contacts.AttachAsModified(contact);
    dataContext.SaveChanges();
}

This is pretty straight forward and certainly not very complex. However, it is promising that EF is moving in the direction of better enabling these simple scenarios as compared with previous versions.

Tweet Post Share Update Email RSS