Search code examples
nhibernategenericsrepositoryfetchfluent-interface

Fluent Wrapper for Nhibernate Fetch ThenFetch


I have a generic repository with a Query Method that returns IQueryable. In my calling code I can then do something like this

_repository.Query<MyClass>(x=>x.EntityId == 1).Fetch(x=>x.MyClassChild).ToList()

However, I would then be unable to test the calling code ( as far as I know ). So I'm trying to do the following

public class Repository : IRepository
{
....
    public FetchedResult<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector)
    {
        INhFetchRequest<TQueried, TRelated> nhFetchRequest = query.ThenFetch(relatedObjectSelector);
        return new FetchedResult<TQueried, TRelated>(this, nhFetchRequest);
    }

    public FetchedResult<TOriginating, TRelated> Fetch<TOriginating, TRelated>(IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
    {
        INhFetchRequest<TOriginating, TRelated> nhFetchRequest = query.Fetch(relatedObjectSelector);
        return new FetchedResult<TOriginating, TRelated>(this, nhFetchRequest);
    }
}

--

public class FetchedResult<TQueried, TRelated>
{
    private readonly IRepository _repository;
    private readonly INhFetchRequest<TQueried, TRelated> _query;

    public FetchedResult(IRepository repository, INhFetchRequest<TQueried, TRelated> query)
    {
        _repository = repository;
        _query = query;
    }

    public FetchedResult<TQueried, TRelated> ThenFetch<TFetch>(Expression<Func<TFetch,TRelated>> relatedObjectSelector)
    {
        return _repository.ThenFetch(_query, relatedObjectSelector);
    }
}

So the first call to Fetch works but the call to repositor.ThenFetch takes an INhFetchRequest query but returns an INhFetchRequest. So I can't then use the FetchedResult to call the ThenFetch a second time.

I think this is the problem. My brain is pretty unraveled at this point. If anyone can help let me know and I can try and give more or better information.

Now I know I can do it using statics however, my goal here is to be able to mock the calls to Fetch.

Thanks,

Raif


Solution

  • Alrighty, my feeble brain has finally grasped the solution. After a boring as hell commute I realized that the problem was with the generics being in on the object level rather then the method level. The following is my solution. I may blog on said matter in which case later I will include the link

    public class Repository : IRepository
    {
    ....
        public FetchQuery QueryFetch<ENTITY>(Expression<Func<ENTITY, bool>> where = null) where ENTITY : Entity
        {
            var query = _unitOfWork.CurrentSession.Query<ENTITY>();
            var queryable = where == null ? query : query.Where(where);
            return new FetchQuery(this, queryable);
        }
    
        public FetchedResult ThenFetch<TQueried, TFetch, TRelated>(INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector)
        {
            INhFetchRequest<TQueried, TRelated> nhFetchRequest = query.ThenFetch(relatedObjectSelector);
            return new FetchedResult(this, nhFetchRequest);
        }
    
        public FetchedResult ThenFetchMany<TQueried, TFetch, TRelated>(INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector)
        {
            INhFetchRequest<TQueried, IEnumerable<TRelated>> nhFetchRequest = query.ThenFetch(relatedObjectSelector);
            return new FetchedResult(this, nhFetchRequest);
        }
    
        public FetchedResult Fetch<TOriginating, TRelated>(IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
        {
            INhFetchRequest<TOriginating, TRelated> nhFetchRequest = query.Fetch(relatedObjectSelector);
            return new FetchedResult(this, nhFetchRequest);
        }
    
        public FetchedResult FetchMany<TOriginating, TRelated>(IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector)
        {
            INhFetchRequest<TOriginating, TRelated> nhFetchRequest = query.FetchMany(relatedObjectSelector);
            return new FetchedResult(this, nhFetchRequest);
        }
    }
    
    public class FetchedResult
    {
        private readonly IRepository _repository;
        private object _query;
        public FetchedResult(IRepository repository, object query)
        {
            _repository = repository;
            _query = query;
        }
    
        public FetchedResult ThenFetch<TQueried, TFetch, TRelated>(Expression<Func<TFetch, TRelated>> relatedObjectSelector)
        {
            return _repository.ThenFetch((INhFetchRequest<TQueried, TFetch>)_query, relatedObjectSelector);
        }
    
        public FetchedResult ThenFetchMany<TQueried, TFetch, TRelated>(Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector)
        {
            return _repository.ThenFetchMany((INhFetchRequest<TQueried, TFetch>)_query, relatedObjectSelector);
        }
    
        public List<TOriginating> ToList<TOriginating>()
        {
            return ((IQueryable<TOriginating>)_query).ToList();
        }
    }
    
    public class FetchQuery
    {
        private readonly IRepository _repository;
        private readonly object _query;
    
        public FetchQuery(IRepository repository, object query)
        {
            _repository = repository;
            _query = query;
        }
    
        public FetchedResult Fetch<TOriginating, TRelated>(Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
        {
            return _repository.Fetch((IQueryable<TOriginating>)_query, relatedObjectSelector);
        }
    
        public FetchedResult FetchMany<TOriginating, TRelated>(Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector)
        {
            return _repository.FetchMany((IQueryable<TOriginating>)_query, relatedObjectSelector);
        }
    
        public List<TOriginating> ToList<TOriginating>()
        {
            return ((IQueryable<TOriginating>) _query).ToList();
        }
    }
    

    usage would be as follows

    _repository.QueryFetch<InternetProfile>(x => x.CompanyId == Id ).FetchMany<InternetProfile, SiteProperty>(x => x.SiteProperties).ToList<InternetProfile>();
    

    I do find that the generic declarations are a bit verbose, but it freakin works and I'm leaving it at that for now. Any suggestions, of course, would be welcome.

    Raif