AttachUpdated command for Entity Framework

#entityframework

Posted by admin on September 01, 2019

So who here has tried to get an entity that is disconnected reattached with all relevant references updated? I know i have… And after scouting the web for solution after solution here are the set of methods that works for me… They are a mismatch better a lot of other people methods, but this seems to be the best combination and so far I have had no problems.

Note : That my entitykeys are usually ‘Id’ so if your are different, then you will need to slightly change the code i.e. where is says ‘Id’

public static class EntityFrameworkExtensionMethods {

<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> AttachUpdated(<span class="kwrd">this</span> ObjectContext ctx, EntityObject objectDetached) {
    <span class="kwrd">if</span> (objectDetached.EntityKey == <span class="kwrd">null</span>) {
        String entitySetName = GetEntitySetFullName(ctx, objectDetached);
        <span class="kwrd">int</span> objectId = (<span class="kwrd">int</span>)objectDetached.GetType().GetProperty(<span class="str">&quot;Id&quot;</span>).GetValue(objectDetached, <span class="kwrd">null</span>);
        objectDetached.EntityKey = <span class="kwrd">new</span> System.Data.EntityKey(entitySetName, <span class="str">&quot;Id&quot;</span>, objectId);
    }
    <span class="kwrd">if</span> (objectDetached.EntityState == EntityState.Detached || objectDetached.EntityState == EntityState.Modified) {
        <span class="kwrd">object</span> currentEntityInDb = <span class="kwrd">null</span>;
        <span class="kwrd">if</span> (ctx.TryGetObjectByKey(objectDetached.EntityKey, <span class="kwrd">out</span> currentEntityInDb)) {
            ctx.ApplyPropertyChanges(objectDetached.EntityKey.EntitySetName, objectDetached);
            ctx.ApplyReferencePropertyChanges((IEntityWithRelationships)objectDetached,
                                              (IEntityWithRelationships)currentEntityInDb);  <span class="rem">//extension</span>
        }
        <span class="kwrd">else</span> {
            <span class="kwrd">throw</span> <span class="kwrd">new</span> ObjectNotFoundException();
        }
    }
}

<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">string</span> GetEntitySetFullName(<span class="kwrd">this</span> ObjectContext context, EntityObject entity) {
    <span class="rem">// If the EntityKey exists, simply get the Entity Set name from the key</span>
    <span class="kwrd">if</span> (entity.EntityKey != <span class="kwrd">null</span>) {
        <span class="kwrd">return</span> entity.EntityKey.EntitySetName;
    }
    <span class="kwrd">else</span> {
        <span class="kwrd">string</span> entityTypeName = entity.GetType().Name;
        var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
        <span class="kwrd">string</span> entitySetName = (from meta <span class="kwrd">in</span> container.BaseEntitySets
                                <span class="kwrd">where</span> meta.ElementType.Name == entityTypeName
                                select meta.Name).First();

        <span class="kwrd">return</span> container.Name + <span class="str">&quot;.&quot;</span> + entitySetName;
    }
}

<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> ApplyReferencePropertyChanges(<span class="kwrd">this</span> ObjectContext ctx, IEntityWithRelationships newEntity, IEntityWithRelationships oldEntity) {
    <span class="kwrd">foreach</span> (var relatedEnd <span class="kwrd">in</span> oldEntity.RelationshipManager.GetAllRelatedEnds()) {
        var oldRef = relatedEnd <span class="kwrd">as</span> EntityReference;
        <span class="kwrd">if</span> (oldRef != <span class="kwrd">null</span>) {
            var newRef =
                newEntity.RelationshipManager.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) <span class="kwrd">as</span>
                EntityReference;

            <span class="kwrd">if</span> (newRef != <span class="kwrd">null</span> &amp;&amp; newRef.EntityKey == <span class="kwrd">null</span>) {
                PropertyInfo info = newRef.GetType().GetProperty(<span class="str">&quot;Value&quot;</span>,
                                                                 BindingFlags.Public | BindingFlags.Instance);
                <span class="kwrd">object</span> val = info.GetValue(newRef, <span class="kwrd">null</span>);
                <span class="kwrd">if</span> (val != <span class="kwrd">null</span>) {
                    <span class="kwrd">string</span> entitySetName = <span class="kwrd">string</span>.Empty;
                    var objVal = val <span class="kwrd">as</span> EntityObject;
                    <span class="kwrd">if</span> (objVal != <span class="kwrd">null</span>)
                        entitySetName = GetEntitySetFullName(ctx, objVal);

                    newRef.EntityKey = ctx.CreateEntityKey(entitySetName, val);
                }
                <span class="kwrd">else</span> <span class="kwrd">if</span> (oldRef.EntityKey != <span class="kwrd">null</span>) {
                    oldRef.EntityKey = <span class="kwrd">null</span>;
                }
            }

            oldRef.EntityKey = newRef.EntityKey;
        }
    }
}
}

You can use this by doing so… Where Student is your EntityObject

public int Save(Student student) {
    using (var context = new sitsEntities()) {
        if ((student.Code != null) && (student.EntityState == EntityState.Detached 
            || student.EntityState == EntityState.Modified))
            context.AttachUpdated(student);
        else if (student.Code == null) {
            context.AddObject(context.GetEntitySetFullName(student), student);
        }

        return context.SaveChanges(true);
    }
}