I have been developing line of business (LOB) applications for more than 10 years by now, and I can tell that in vast majority of cases it is all about Search and basic data manipulations or simply CRUD (CRUD stands for Create, Update, Delete). Yes, sometimes you need to do funky stuff like workflows, but 90% is still CRUD, Search, CRUD, Search, CRUD and Search…
And in real life this CRUD is not simple one/two tables (favourite for demoing stuff) – one UI screen to do data manipulations. It is usually very complex object graphs (or composites) on the server with complex UI as a frontend. Lots of interrelated tabs, lists, sub lists, one-to-many, many-to-many and all the hell of relational modelling behind.
Let’s see how latest bits of WCF RIA (RC at the moment) address simple (and not so simple) CRUD operations over composites.
As WCF RIA developer you have to be aware of Compositional Hierarchies Simple speaking, you can define a "part-of" relationship inside you metadata by using [Composition] attribute. This will affect client-side generated entities behaviour (changes to leaf element will pop up changed flag thru object graph to root element) and server side (you can use ChangeSet.GetAssociatedChanges to retrieve associated changes). There is great post about it here
Ok, enough theory, let’s give it a go. Consider this object graph
Pretty simple, right? Just two levels of hierarchy, each element of List1 has two sub lists. (In my current project we have 3 levels of sub lists on average and up to 10 lists per hierarchy). Anyway, EF model is created, metadata is defined as
Great, almost 200 lines of code were generated for ComplexCompositeService class. We need to slightly tweak it to load the whole object graph though
Now it’s time to quickly model simplest UI for basic CRUD. It looks like this
Will it work? Of course NOT! ;) And the reason is – almost 200 lines of generated code. Have I told you I hate code generators and usual cr@p they produce? In this particular example generated code is
- ugly formatted
- doesn’t work
what a wonderful combination ;) However let’s explore why it doesn’t work and how to fix it. Do simple test – add new element into List1 and press Save. Boom! Exception fires here
unfortunately, this.ChangeSet.GetOriginal(currentRoot) is null for root element (it makes sense because it wasn’t physically modified, it was just marked as modified when we added new sub elements to composite) and AttachAsModified fails. Ok, it’s easy to fix
Great! Now we can save! Don’t be too excited though ;( Make test a bit harder – add two new lines to List1. Boom! Same place, different exception ;) Now it’s EF refuses to attach root element with two new sub items (we’ll discuss this amazing EF behaviour [I’d rather call it nasty bug] in later posts). Ok, I am tired of fighting these endless problems. The bottom line is – the code generated by RIA project template is useless for composites and complex CRUD.
But don’t run and hide! There is solution. And this solution is as simple as this
yes, zero lines of code is all you need! ;)
ok, let me explain how this magic works.
the basic idea is simple – generalise base CRUD operations and base querying based on composition scope defined by Include and Composition attributes.
First of all for composites you can expose only methods for your composite's root entity Update, Insert, Delete and using ChangeSet.GetAssociatedChanges apply the whole changeset to EF ObjectContext
It might seems as a bit of voodoo code, but actually it’s quite simple – we just recursively traverse change set and apply proper entity state to EF unit of work
Secondly – common Get
again – simple idea – instead of doing ObjectContext.Roots.Include("List1.List2").Include("List1.List3");
we build eager loading scope automatically based on composition scope definition metadata
And the best part is – it works. For any change set, any object graph. Out of the box.
…to be continued (how to extend base CRUD of CompositeServiceBase with your custom logic)