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">"Id"</span>).GetValue(objectDetached, <span class="kwrd">null</span>);
objectDetached.EntityKey = <span class="kwrd">new</span> System.Data.EntityKey(entitySetName, <span class="str">"Id"</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">"."</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> && newRef.EntityKey == <span class="kwrd">null</span>) {
PropertyInfo info = newRef.GetType().GetProperty(<span class="str">"Value"</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);
}
}