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