As you may know, in the most recent ria services beta release complex types were introduced which can be used for invoke operations and as entity properties. For additional information i’d advise you to check the following link:
Now why is this of interest?
The rant, skip this part if you just want to go to the problem
When i designed my system i had to make a few decisions, 2 of which being:
1. What ORM i’m going to use – i went with NHibernate
2. Presentation model or exposing my domain models – i went with presentation model, even though RIA Services makes it REALLY easy to do it the other way.
I ended up with the most robust model but it came at the price of writing a lot of boilerplate code (well, in my case, i wrote a lot of code generation templates, but more on that in one of the later posts:). Not sure if it’s the right route for everyone, but i do feel good about it now, it’s really nice and robust although it did introduce some difficulties and i had to do a LOT of research, learning and bending. I really believe it’s going to pay off in the future, or so i hope:).
Some of you may ask themselves why in the world did i choose this kind of approach, why didn’t i go with just using EF and domain models and use Pms when need arises?
Well the answer is this: I wanted to test the platform’s enterprise limits.
Firstly, EF vs NHibernate
I read through huge amounts of documentation, i didn’t try much of the EF, but wherever i read, i saw people basically trying out EF and going back to NH. Also, nhibernate was based on much healthier principles, the resulting code being much cleaner and attribute free. Also i am very handy with code generation, i developed my custom code generation template (which i’m very proud of) for nhibernate and fluent nhibernate, so i could get best of both worlds that way. I also knew there was a linq provider for NH getting down the pipeline which would be very good, so the decision was NH.
Second, Presentation Model vs Domain Model
It was also a product of a lot of reading and going through different blogs, most of them were really heavy advocates of not exposing the domain model. In the end, what made me go Pm route is a fairly robust support from Ria framework and the fact that domain model will potentially get really complicated really fast.
Ok so here we are, NH and PM all the way, enterprise stuff! And Ria services:)
The problem
One of the problems i faced recently is how to make peace between client side linq queries, presentation model and nhibernate linq provider.
Example: i have to fetch partner with all the notes related to partner, map both of it to respective presentation models (PartnerPm and PartnerNotePm), do paging and potentially any other additional queries, all on database level.
If you are using Entity Framework and exposing domain models, i think this kind of problem would be pretty easy to solve, but when using the “enterprise” combination i chose, things get pretty hairy very fast!
The biggest problem is that when you do those client side linq queries you are doing them on the presentation model, not the domain model! Well, nhibernate is sometimes smart enough in this regard, he can figure it out for simpler queries. That basically means that all your “where” queries would get executed after fetching data from database, or you would just get some kind of strange error trying to do something like that. The other problem would be combining prefetching and paging. If you want to prefetch some child records and do paging you’re basically stuck with two separate queries, which needs some custom attention.
NH linq provider is not quite there yet, and exhibits some strange behaviour which really isn’t very reliable for chaining the calls. If you are using Presentation model AND EF there are some workarounds, one that is explained in Colin’s excellent blog:
Not sure if this would work with Nhibernate, but i just couldn’t be bothered to test it out. The problem which i have with this approach is that you are again exposing the domain model although you are not filling it with data.
The solution
So i decided to ditch client side queries in general because they only introduced problems to fetching data. I decided to go with passing arguments to server methods. This goes well with preffered patterns and practices the only problem i have with this approach is that server methods would look something like this:
public IEnumerable<PartnerPm> GetPartnerListWithNotes(string partnerName,int skip, int take, out int count)
This would be a method which would support paging and filtering by partnerName. Now if you wanted to filter by some other parameter, you would have to change the method signature, or you would have to overload it.
public IEnumerable<PartnerPm> GetPartnerListWithNotes(string partnerName, string country, int skip, int take, out int count)
…and on and on and on. you’d have to add skip, take and count every time, increasing fatigue and irritation with every new method. Not cool.
The solution to the problem would be:
public IEnumerable<PartnerPm> GetPartnerListWithNotes(PartnerCriteria partnerCriteria, out int count)
PartnerCriteria is an object containing all of the information like skip take and any other data needed. Not still sure about the count, but it’s not a huge problem overall to have it at the end of method.
Now, this would all be nice if Ria allowed custom user type arguments. The closest you can get the above example would be:
public IEnumerable<PartnerPm> GetPartnerListWithNotes(string partnerCriteria, out int count)
So what you’re stuck with is doing some serialization
public IEnumerable<PartnerPm> GetPartnerListWithNotes(string partnerCriteria) { var criteria = partnerCriteria.DeserializeJson<PartnerCriteria>(); return Repository.Query<Partner>().Where(x=>x.Name==criteria.PartnerName).FetchMany(x=>x.PartnerNotes).ToList().Select(FormatPartner); }
Ok, so it’s basically serializing data on the client side and deserializing it on the server side. The only thing you need to have is a shared PartnerCriteria class
PartnerCriteria.shared.cs
On client side it would look something like this:
context.Load(context.GetPartnerListWithNotesQuery(SerializeJson(new PartnerCriteria{PartnerName="Altinet"})));
And you’re set:) I think you can take it from there. Or not? Well in the next post i’ll have some implementation explained, plus a way to make the whole thing (almost) totally type safe and easy to use. Back soon!
Leave a Comment