This project is read-only.

Best way to add "Per-call"/"OneTime" UnitOfWork to NCommon

Mar 22, 2009 at 9:31 PM

In some situations it might be usefull to be able to make a simple query over a repository w/o needed to declare a UoW scope.
I'm refering to this situation in which you will only make one query agains the repository and/or when you dont need any kind of transaction (like when only reading data).
I'm thinking on which will be the best way to accomplish this task, so If I call Query on a IRespository it will try to find an ambient scope and if not found it will create on by itself, closing it just before returning.

What do you think about?
Mar 25, 2009 at 4:30 AM
Edited Mar 25, 2009 at 4:37 AM

First of all I think allowing repositories to start a UOW scope when an explicit one hasn't been started is not a good idea. Allowing repositories to create manage their own private uow instances delegate control of uow from the application scope into the repositories, which is never a good idea. Repositories should only be used within an explicit unit of work scope, managed by the application or service layer. 

Regarding querying without the need for transactions it is always recommended that even queries should run within an explicit transaction that is managed by the application. I would recommend reading Oren's [Ayende's] post on transient transactions http// Although the post is about NHibernate, the same applies to L2S and EF as well.

The other problem with the above approach is the nature of how Linq works. When you query on the repository you are generating an IQueryable instance that will be executed when the instance is enumerated over which could be at a later stage or the query can be combined with other IQueryable instances to form an aggregated query. This means that if the repository is creating and managing the UOW instances, which means that it will create one at the time of Query and once the query is constructed it will close the uow. When the query instance is enumerated over an exception will be generated as the context has been disposed off as the unit of work associated with the LINQ query has been disposed. 

Now, if the unit of work needs to live beyond the lifecycle of just returning the IQueryable instance then you would have to create a wrapper IQuery instance that would keep the unit work that was used to construct the query until the time the query has executed i.e. iterated. Things can get quite complex from then on...

In any case, I've made the GetCurrentUnitOfWork method on the RepositoryBase virtual so that you can override the default behavior which is to look for an existing ambient unit of work to meet your needs. This change is in the latest source.

Mar 25, 2009 at 12:28 PM

In the end, I think that I agree with you.. It's just that some times the dark side shadows over me ;)