I’m using a generic repository that exposes an IQueryable<T> like this:
public IQueryable<T> AllEntities
{
get
{
return session.Query<T>();
}
}
I can query like this:
var results =
(from e in repository.AllEntities
where e.SomeProperty == "some value"
select e).ToList();
However, if T has a parent and grandparent entity and I want to load them eagerly, I have to do this:
var results =
(from e in repository.AllEntities
where e.SomeProperty == "some value"
select e)
.Fetch(x => x.Parent)
.ThenFetch(x => x.Grandparent)
.ToList();
This works, but .Fetch and .ThenFetch are both Linq2Nhibernate specific extension methods, which is causing two problems:
-
I have to include a
using NHibernate.Linq;statement at the top of my file. However, at the point that I’m doing this query, it should be implementation agnostic. -
When I try to unit test this, the
.Fetchand.ThenFetchmethods fail when executed against theIQueryable<T>that my mock repository provides.
How can I wrap these inside of my IRepository<T> interface, or inside of some generic extension methods?
Update:
So far all I’ve come up with is to add this to my repository interface:
IQueryable<T> EagerLoadParent<U>(IQueryable<T> query,
Expression<Func<T, U>> parentExpression);
IQueryable<T> EagerLoadParent<U, V>(IQueryable<T> query,
Expression<Func<T, U>> parentExpression,
Expression<Func<U, V>> grandparentExpression);
… and this to my NHibernate repository implementation:
public IQueryable<T> EagerLoadParent<U>(IQueryable<T> query,
Expression<Func<T, U>> parentExpression)
{
return query
.Fetch(parentExpression);
}
public IQueryable<T> EagerLoadParent<U, V>(IQueryable<T> query,
Expression<Func<T, U>> parentExpression,
Expression<Func<U, V>> grandparentExpression)
{
return query
.Fetch(parentExpression)
.ThenFetch(grandparentExpression);
}
The consumer of this API now does this:
var query =
(from e in repository.AllEntities
where e.SomeProperty == "some value"
select e);
var results = repository
.EagerLoadParent(query, e => e.Parent, p => p.Grandparent)
.ToList();
But this lacks the nice extension method syntax I’d prefer. I’m looking for something closer to the .Fetch and .ThenFetch syntax.
After some investigation I think I have a recipe: simply follow closely
NHibernate.Linqimplementation in order to have your own implementation and avoid an explicit NHibernate.Linq dependency in your client code. You just need to reproduce very closelyNHibernate.Linq.EagerFetchingExtensionMethodsclass.It takes an interface:
IFetchRequest, a classFetchRequestimplementingIFetchRequestand a static classEagerFetchimplementing extension methods. This is a sort of clone ofNHibernate.Linq.EagerFetchingExtensionMethodsclass.Just define:
which mimics
NHibernate.Linq.INhFetchRequest<TQueried, TFetch>then define an implementation:
This one simply holds a nHibernate implementation and forwards every method to that member.
Finally: