This is the code to accomplish that:
public static class UnitTestFriendlyNhFetching
{
public static IQueryable<TOriginating> NhxFetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
{
// Prior to NHibernate 3.2, use NhQueryProvider
// (query.Provider is NHibernate.Linq.NhQueryProvider)
if (query.Provider is NHibernate.Linq.DefaultQueryProvider)
return query.Fetch(relatedObjectSelector);
else
return query;
}
public static IQueryable<TOriginating> NhxFetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector)
{
// Prior to NHibernate 3.2, use NhQueryProvider
// (query.Provider is NHibernate.Linq.NhQueryProvider)
if (query.Provider is NHibernate.Linq.DefaultQueryProvider)
return query.FetchMany(relatedObjectSelector);
else
return query;
}
}
Example use:
public class MovieController : Controller
{
IRepository<Movie> _rm = null;
public HomeController(IRepository<Movie> rm)
{
_rm = rm;
}
public ViewResult Index()
{
// NHibernate NhxFetchMany won't complain even if _rm.All came from mocked IQueryable only
return View(_rm.All.Where(x => x.Title == "Thor")
.NhxFetchMany(x=> x.Quotes));
}
}
This is the repository interface
public interface IRepository<Ent> where Ent : class
{
IQueryable<Ent> All { get; }
void Save(Ent ent, byte[] version);
void VersionedDelete(object id, byte[] version);
Ent LoadStub(object id);
string PrimaryKeyName { get; set; }
string VersionName { get; set; }
}
The code above can work on aggregate root only, i.e. it can only fetch the children and parent of a given aggregate root, but it cannot further fetch the grandchildren of an aggregate root; ThenFetch and ThenFetchMany can only be chained after Fetch and FetchMany.
If we can find how to cast IQueryable to NHibernate's INhFetchRequest<TOriginating, TRelated>, then we can include unit testing-friendly extension methods for grandchildren entities
No comments:
Post a Comment