Since my last post on the NCommon project, I’ve been looking at using NCommon as the base framework for Rhinestone. Jumping back into Rhinestone I realized that I first need an implementation of RepositoryBase and UnitOfWork for NHibernate. I decided to go ahead and create implementations of RepositoryBase and UnitOfWork for NHibernate, Linq To SQL and Entity Framework (that last one giving me the most head ache). While developing these implementations, some changes were made to NCommon.

Here are some of the changes.

  • Save on IRepository changed to Add and Update

While implementing RepositoryBase for Linq to SQL and Entity Framework, it was obvious that the single Save method won’t work. Both don’t have a way to identify new entities on their own and rely on the consumer to tell weather to insert or update the entity.

In some ways this makes sense because some complex entities may have unique ways to identify a new entity, but there is almost always a single identifying property or field that marks the state of an entity. NHibernate deals with this scenario by using the unsaved-value attribute either on the Id element or on the version element. That allows NHibernate to easily identify new entities as opposed to existing ones.

Since both Linq and EF don’t have any such smarts in them, the only way to maintain infrastructure ignorance on the base class was to split Save into two separate functions Add and Update.

For a brief while I was considering adding an additional interface, called IEntityStateProvider with one method IsNew(TEntity entity), that would be injected into the LinqToSqlRepository or EFRepository and would be used to identify if an entity is new or not. That didn’t fly because that would mean that if I had a complex domain with a multitude of entities, I didn’t want to sit around and create IEntityStateProvider implementations for each entity just to find its effin state.

The other approach I was toying around is to use something like a Func<TEntity entity, bool> delegate that the repository could call to check if the entity being passed in Save is new or not. If this delegate was not specified then it would use the Contains extension to query the underlying IQueryable to see if that entity already exists. That mean that if the delegate was not specified, every time Save is called the database would be hit with a useless Exists call.

I just ended up splitting the damn method to Add and Update to keep things simple.

  • Added a With method to allow eager loading of entities

One of the things that was missing from the original IRepository interface was to allow a way to specify eager loaded entities. Almost all ORM’s provide a way to specify entities to eager load when evaluating a query. The challenge was to decide the method signature.

NHibernate provides a method called Expand that takes in a string that represents the path of the entity to eager load.

Similarly, Entity Framework has a method called Include that again takes in a string that represents the path of the entity to eager load.

Obviously, Linq to SQL had to do it differently. It uses a class called DataLoadOptions that has  method LoadWith It instead accepts an expression. This DataLoadOptions class is then associated with the DataContext :)

Actually I liked the way Linq to SQL uses the Expression<Func<TEntity entity, objhect>> to specify what entities to re-load. It provides a compile time check where as in NHiberate and Entity Framework, if the underlying property name was changed you’d end up getting errors.

The method signature of With method in IRepository is:

  • With(Expression<Func<TEntity entity, object>> path)

Obviously since both NHibernate and Entity Framework require a string path, I had to convert the expression into a string represented path. To do this, I added a MemberAccessPathVisitor, inheriting from ExpressionVisitor, to NCommon. Calling Visit() on this class will analyze the expression and build a path string which can be obtained using the Path property of the visitor.

This MemberAccessPathVisitor is made public in case you need to create an implementation of IRepository for a ORM framework that expects eager loaded paths as strings.

  • Added Detach, Attach, Refresh methods on IRepository

I got a comment on one of my previous posts to consider adding Detach, Attach and Refresh methods on the UnitOfWork. Although I disagree that those methods belong on the UnitOfWork, they do make sense on the repository. The Unit of Work’s role is to act as a singe unit boundary where all actions within that unit are accepted or not accepted. It really should not be concerned with the state of a entity.

Instead, those methods completely make sense at the Repository level because the Repository should most definitely concerned with the state of an entity. You would use the Repository to retrieve and update entities, it would make sense to use the Repository to attach, detach and also refresh entities.

I’ve added these methods to the IRepository<TEntity> interface and also provided implementations for them in the NHibernate, Linq To Sql and Entity Framework implementations. Since Linq To SQL doesn’t really allow Detaching entities, entities are detached when the DataContext goes out of scope, calling Detach on the Linq to SQL implementation throws a NotSupportedException.

  • Added sub namespaces to provide logical separation

Another suggestion I received to move the separate patterns into their own namespaces. At first I was opposed to the idea because I didn’t believe there was too much complexity there… I was wrong. While developing the different implementations for RepositoryBase, I realized that providing a logical separation via namespaces would provide less clutter.

So here’s the structure now;

  • Repository and UnitOfWork are under NCommon.Data namespace
  • Specifications is under NCommon.Specifications namespace
  • Business and Validation rules are under NCommon.Rules namespace
  • Storage classes (Application, Local, Session) are under NCommon.Storage namespace. The Storage class has been renamed to Store so that there is no clash between namespace and class name.
  • New NCommon.Extensions namespace to contain with common extensions.
  • New NCommon.Expressions namespace contains the ExpressionVisitor class and future implementations for ExpressionVisitor to help process expressions.

Beyond the above changes there are some bug fixes that I found while developing the implementations for RepositoryBase and UnitOfWork. I’ll be posting a how-to post on how to (duh) use the implementations of RepositoryBase and UnitOfWork.

Keep an eye out on future blog posts on Rhinestone where I’m going to start using NCommon to flesh out the project.

As always, if you have any suggestions on NCommon please add a comment. 

Posted on Friday, December 12, 2008 10:57 AM | Filed Under [ NCommon NHibernate Linq Entity Framework ]


Comments

Gravatar
# Hi Luca,<br><br>Check out my latest post. It has s...
Posted by Ritesh Rao
on 1/16/2009 5:14 AM
Hi Luca,<BR/><BR/>Check out my latest post. It has some details on a sample app I am working on that might help you.
Gravatar
# Hi, nice work, <br><br>How I can setup a sample we...
Posted by Luca Milan
on 1/12/2009 11:40 PM
Hi, nice work, <BR/><BR/>How I can setup a sample web app with NCommon starting from Global.aspx file for example? Can you post some code ?<BR/><BR/>Thx
Gravatar
# Ritesh,<br><br>I haven't checked out the tests but...
Posted by Chris Martin
on 12/15/2008 6:50 PM
Ritesh,<BR/><BR/>I haven't checked out the tests but, make sure you check the generated SQL. The "order by" just plain ol' wasn't being generated for me without changing the Query method to return IQueryable.
Gravatar
# Once again awesome stuff! Any advice on creating ...
Posted by justin
on 12/13/2008 5:10 PM
Once again awesome stuff! Any advice on creating provider agnostic poco's? NHibernate supports this pretty well but L2S and EF probably need a bit of hackery.
Gravatar
# Chris<br>===================<br>Could you post you...
Posted by Ritesh Rao
on 12/12/2008 8:46 PM
Chris<BR/>===================<BR/>Could you post your scenario where you weren&#39;t able to use orderby to order a repository while using the Query method?<BR/><BR/>I&#39;ve added some additional tests to NCommon&#39;s source to test querying repository using a Specification and then ordering the results using orderby. Here is the test added for NHibernate:<BR/><BR/>using (new UnitOfWorkScope())<BR/> {<BR/> var customersInPA = new Specification&lt;Order&gt;(x =&gt; x.Customers.State == &quot;PA&quot;);<BR/><BR/> var ordersRepository = new NHRepository&lt;Order&gt;();<BR/> var results = from order in ordersRepository.Query(customersInPA)<BR/> orderby order.OrderDate<BR/> select order;<BR/><BR/> Assert.That(results.Count() &lt; 0);<BR/> }<BR/><BR/>The tests run fine so I&#39;m not sure why you are not able to use orderby along with a Specification instance. I&#39;ve committed the tests in SVN so you can take a look.<BR/><BR/>Thanks!<BR/>Ritesh
Gravatar
# That would be *Query* not Find. I renamed the meth...
Posted by Chris Martin
on 12/12/2008 7:34 PM
That would be *Query* not Find. I renamed the method. ;)
Gravatar
# You&#39;ve done good with the Repository code.<br>...
Posted by Chris Martin
on 12/12/2008 7:15 PM
You&#39;ve done good with the Repository code.<BR/><BR/>The only thing I had to change was IEnumerable&lt;TEntity&gt; Find(ISpecification&lt;TEntity&gt; specification);<BR/><BR/>to<BR/><BR/>IQueryable&lt;TEntity&gt; Find(ISpecification&lt;TEntity&gt; specification);<BR/><BR/>before, the orderby keyword wasn&#39;t working. With that change, it does.
Gravatar
# re: Update on NCommon
Posted by replica watches
on 1/2/2012 9:33 PM
thanks for sharing this..x
Post Comment
Title *
Name *
Email
Url
Comment *  
Please add 8 and 2 and type the answer here: