Wednesday, September 3, 2008

Entity Framework and some Architectural Decisions

I recently read an article on getting around how Entity Framework works in regards to trying to simulate it into the MVC Storefront app that Phil Haack did a video series on recently. Muhammad Mosa does an excellent job writing on the same experiences I faced when trying to mock up a architecturally sound design utilizing Entity Framework (swapping out Linq to Sql).

In this article, Muhammad mentions 2 ways to get around the short comings of what it can project client side vs server side and how to map that into a Repository that flows with fluent filters as extension methods like the MVC Storefront application series.

The first way he mentions is the Virtual Proxy pattern class that wraps the entity object, and allows you to lazy load its references and the object itself when you reference its properties.

The second way is to explicitly define a complex projection (the select new from a Linq statement into another typed object - such as a data transfer object (DTO)) as a client side query with the AsEnumerable method, to pull all of the data from the database into memory to do some complex shaping, but leave its child references as IQueryable to lazy load.

Please refer to the above link to read Muhammad's article to get a clearer picture of what this means.

I decided to discuss these approaches in the comments, and realized how long the comment got, so I wanted to post it here for any readers to join in the discussion, so that hopefully, we can come up with a cleaner solution.

Entity Framework Architectural Discussion

The bad thing about the second way (i.e. the Client side evaluation), besides the mass amounts of data you need to pull into memory, is that now you are segregating your methods into some, like GetCategory7() with a AsEnumerable() and the GetProducts() with no AsEnumberable(). So you are segregating how you handle each pull from the Data Store based on what is the Main object, and its child references, which isnt all that bad if you have a repository per main object call.

However, supposebly you would have a Product Repository which has to duplicate what you are pulling from your Category Repository but with an AsEnumerable to correctly shape it.

This will make for duplicate logic in pulling data depending on if you need that entity as a child reference or base object.

Based on that alone, I would stick with the first option, which is basically a Virtual Proxy Pattern on top of each entity object. The problem here is the mass amount of mock up for each Property, especially when you already went through the trouble of creating your Model in the EDM. Now you have do it through the Entity Framework Model, and your wrapper proxy class, every time something changes. Again, excessive duplicate work.

Unfortunately, I hate to say it, but the third way it seems is just using Entity Framework as the Repository object that calls into each entity is probably the less work way, but couples you completely to EF. You can then marry your Business rules and logic to the partial of each entity. This also allows you to utilize ADO.NET Data Services in a seamless way to expose your domain layer to multiple applications (which you can do with the first and second way but you will need to implement IUpdateable in your Repository -> which can be a pain).

There is no "utimate" way to do this at this time. But to me, saving work up front, especially when it could change for v2 is probably a simpler way. But layered wise, the proxy pattern approach is definately more architecturally sound, the problem is you are back to building out your DTO objects that match your entity model, basically regurgitating out each new property in your proxy DTO class.

I dont know, but for situations where I want to utilize ADO.NET Dataservices, approach 3 seems the better route now, I just hope when POCO objects make there way, I dont get burnt in having to re-write much.

Essentially, the typical data layer model has you making a Repository Layer, a Service Layer (your business layer), and the application Layer (your MVP/MVC layer).

By utilizing EF at the Repository Layer, you completely couple yourself at that layer to EF, but gain the flexibility to easily change your model independently from your data schema (which is typically what the Repository does anyway).

I am testing out using the ADO.NET DataService as the service layer, since you can inject before query calls, and on updates/creates/etc. Unfortunately, to fully utilize my rules logic, it is simpler to push that into the partial for each entity, and throw an exception which I can trap in the DataService layer and respond out.

From there my Applications Model Layer in a MVC application will handle making a Application Business Layer that is specific for that application that simply consumes the ADO.NET Data Service to get the data and utilize the entity in the application. So rather than trying to make my Domain Layer with EF/ADO.NET Data Services be the business rules for everything, it just handles making sure my domain rules are correct for my model, and the application itself handles business rules that are correct for that specific application (since this model is for multiple applications to consume this -- it cant be everything to everyone, but it can make sure it is valid at a domain layer).

Hope this helps, this is just some of the things I have played around with. Maybe we can poke holes in both our ideas enough to come up with a cleaner solution.

1 comment:

Muhammad Mosa said...

Nice discussion Corey. As you noticed, the repository is used to query the the Entity Objects. It is building the LINQ queries in its methods. Then there are Service Classes which use the repository ones. And both work with the Model Classes (Business Objects). But only repository work with EF. Which exactly what I want. I made all EF generated classes as internal classes so they can be only used from within the library itself.
Thank you for sharing your ideas.