views:

148

answers:

2

I’m using NHibernate for data access, but accessing it through a façade layer. This layer consists of interfaces for the repositories, plus an IUnitOfWork interface which corresponds to the ISession object.

In order that retrieved entities are managed correctly, repositories are passed an IUnitOfWork in their constructor and the IUnitOfWork is used for the loading.

The IUnitOfWork contains a property called All, which retrieves all entities of the class as an IQueryable (for later filtering). Thus, a repository method to retrieve all entities created this year might look like the following:

NB: this is not the complete code for these interfaces and classes! Only the code relevant to my question.

IUnitOfWork interface:

IQueryable<T> GetList<T>();

UnitOfWork concrete class:

public IQueryable<T> GetList<T>()
{
  return _session.Linq<T>();
}

IFooRepository interface

IQueryable<Foo> All { get; }
IEnumerable<Foo> ThisYearsFoos{ get; }

FooRepository concrete class

public IQueryable<Foo> All
{
  get { return _unitOfWork.GetList<Foo>(); }
}

public IEnumerable<Foo> ThisYearsFoos
{
  get { return All.Where(x => x.DateCreated > new DateTime(2010,1,1);}
}

I would like to add functionality to specify fetch strategies so that related entities can be eagerly loaded. So let’s say Foo has a property corresponding to another entity, Bar:

public class Foo
{
    public Bar {get;set;}
}

The mapping file specifies that Bar is lazy-loaded, but in my ThisYearsFoos repository property I would like to specify that Bar should be eagerly loaded to avoid N+1 selects.

In Linq to NHibernate we can specify eager fetching using the Expand() extension method. However, this extension method belongs to the NHibernateQueryable type, whereas the IUnitOfWork interface’s GetList method only knows about IQueryable.

Clearly I don’t want the IUnitOfWork interface to know about INHibernateQueryable since it is supposed to not know about NHibernate.

Using the design I have specified above, is there a way to do this that I haven’t been able to think of? Or is my design in need of a rethink?

Thanks

David

A: 

You are saying some conflicting things: - You don't want to expose interface - You want to use the use that interface

That is impossible. You have to rethink your design. You use the term unit of work for a different thing than most people do. Most people would expect a unit of work interface to have the methods Commit and RollBack, but not some IQueryable.

Paco
I haven't specified the full code for these classes and interfaces! Only the bits that are relevant to my question!
David
That makes sense about the unit of work. I still think you have to rethink your design because you want to conflicting things.
Paco
I don't think I'm trying to do conflicting things. Can you tell me what you mean?
David
You say you want to use some functionality outside a class and you do not want to expose that functionality outside that class. I don't know how to explain it better. Diego's suggestion will probably do what you want.
Paco
I suppose in a sense what you're saying is the core of my problem. I only want to expose an IQueryable (since it's not specific to NHibernate), but the functionality I want isn't available through an IQueryable - except in NHibernate 3, as Diego said. But I was also interested whether the problem stemmed from bad design. (Which I suspect it may.)
David
+1  A: 

Upgrade to NHibernate 3.x. The new method that corresponds to Expand (Fetch) operates on IQueryable.

Diego Mijelshon
Now that's the answer!What state is NHibernate 3 in though?
David
It's pretty stable.
Diego Mijelshon