Showing posts with label WCF RIA Services. Show all posts
Showing posts with label WCF RIA Services. Show all posts

Thursday, March 31, 2011

WCF RIA Services Compositions with Entity Framework

I haven't been working on anything outside Genexus, Deklarit and Genexus Server for a while, so when my friend Mateo asked to help him on a new project for a client of his, based on brand new Microsoft technologies, I was saying yes before the end of the sentence.

This blog post and probably some more to come will be related to our experience with Entity Framework 4, RIA Services 1 and Silverlight 4.

But in this particular case I wanted to blog about a problem we had with Compositions. Compositions are very useful when you have an Association where a Parent entity needs to have its children all the time.

The Update method of parent entities is a bit different than regular entities. I took the patter from this article (Compositional Hierarchies) but things didn’t work as expected. I have to add that “m generating POCO entities and using the Unit Of Work pattern so it wasn’t easy just copy and paste the code for the article. I posted a few questions to the RIA services forum and found out that that pattern exposed a bug :(

Fortunately I was redirected this post from Brett Samblament which described the new pattern to follow to write a fully functional UpdateParent method. But again, I can’t just copy and paste, so here’s the code I wrote for it. Also, by using generic, I’m able to call the exact pattern for every composition in my model, cool uh?!

public void UpdateParent(Parent parent)
{
EntityHelper.UpdateParentEntity(parent, ObjectContext.Parents, ChangeSet, ObjectContext);

foreach (Child child in ChangeSet.GetAssociatedChanges(parent, o => o.Children))
EntityHelper.UpdateChildEntity(child, ObjectContext.Children, ChangeSet, ObjectContext);

}


And my EntityHelper class has the following methods:



public static void UpdateParentEntity<T>(T entity, IRepository<T> repository, ChangeSet chgSet, IUnitOfWork oc)
where T : class
{
try
{
ObjectContext ctx = oc as ObjectContext;
repository.ObjectSet.AddObject(entity);

T originalEntity = chgSet.GetOriginal<T>(entity);

if (originalEntity == null)
ctx.ObjectStateManager.ChangeObjectState(entity, EntityState.Unchanged);
else
repository.ObjectSet.AttachAsModified(entity, originalEntity);
}
catch (Exception ex)
{
TraceManager.Error(string.Format("An error occurred updating a {0}", typeof(T)), ex);
throw;
}
}


public static void UpdateChildEntity<T>(T entity, IRepository<T> repository, ChangeSet chgSet, IUnitOfWork oc)
where T : class
{
try
{
ObjectContext ctx = oc as ObjectContext;
ChangeOperation change = chgSet.GetChangeOperation(entity);

switch (change)
{
case ChangeOperation.Delete:
if (GetEntityState(entity, ctx) == EntityState.Detached)
repository.ObjectSet.Attach(entity);
ctx.DeleteObject(entity);
break;
case ChangeOperation.Insert:
// do nothing
break;
case ChangeOperation.None:
ctx.ObjectStateManager.ChangeObjectState(entity, EntityState.Unchanged);
break;
case ChangeOperation.Update:
T original = chgSet.GetOriginal<T>(entity);
if (original == null) { throw new Exception("Update with no original value found"); }
if (GetEntityState(entity, ctx) == EntityState.Detached)
repository.ObjectSet.Attach(entity);
repository.ObjectSet.AttachAsModified(entity, original);
break;
default:
break;
}
}
catch (Exception ex)
{
TraceManager.Error(string.Format("An error occurred updating a {0}", typeof(T)), ex);
throw;
}
}


public static EntityState GetEntityState(object entity, ObjectContext ctx)
{
System.Data.Objects.ObjectStateEntry ose;
if (ctx.ObjectStateManager.TryGetObjectStateEntry(entity, out ose))
return ose.State;
else
return
EntityState.Detached;
}


I hope this helps someone clear the way… and I promise I’ll post more (and more often) about this.



As usual, this code is ‘works on my machine’ certified.



works on my machine



I never get tired of this Smile

Read Full Post