如何在我的抽象存储库中包装Linq2NHibernate的.Fetch和.ThenFetch?

Sco*_*ock 15 repository linq-to-nhibernate eager-loading

我正在使用一个暴露IQueryable<T>这样的通用存储库:

public IQueryable<T> AllEntities
{
    get
    {
        return session.Query<T>();
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以像这样查询:

var results =
    (from e in repository.AllEntities
     where e.SomeProperty == "some value"
     select e).ToList();
Run Code Online (Sandbox Code Playgroud)

但是,如果T有父母和祖父母实体并且我想急切地加载它们,我必须这样做:

var results =
    (from e in repository.AllEntities
     where e.SomeProperty == "some value"
     select e)
    .Fetch(x => x.Parent)
    .ThenFetch(x => x.Grandparent)
    .ToList();
Run Code Online (Sandbox Code Playgroud)

这工作,但.Fetch.ThenFetch都Linq2Nhibernate特定扩展方法,这是造成两个问题:

  1. 我必须using NHibernate.Linq;在我的文件顶部包含一个声明.但是,在我正在进行此查询时,它应该是与实现无关的.

  2. 当我尝试对此进行单元测试时,.Fetch和我的模拟存储库提供的.ThenFetch方法相比,和方法失败IQueryable<T>了.

如何将这些内容包装在我的IRepository<T>界面内或某些通用扩展方法中?

更新:

到目前为止,我所提出的是将其添加到我的存储库界面:

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);
Run Code Online (Sandbox Code Playgroud)

...这对我的NHibernate存储库实现:

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);
}
Run Code Online (Sandbox Code Playgroud)

此API的使用者现在执行此操作:

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();
Run Code Online (Sandbox Code Playgroud)

但这缺乏我更喜欢的好的扩展方法语法.我正在寻找更接近.Fetch.ThenFetch语法的东西.

gui*_*ido 14

经过一番调查后,我认为我有一个方法:只需密切关注NHibernate.Linq实现,以便拥有自己的实现,并避免在客户端代码中明确的NHibernate.Linq依赖.你只需要非常紧密地重现 NHibernate.Linq.EagerFetchingExtensionMethods课程.

它需要一个接口:IFetchRequest,一个FetchRequest实现的类IFetchRequest和一个EagerFetch实现扩展方法的静态类.这是一种类的克隆NHibernate.Linq.EagerFetchingExtensionMethods.

只需定义:

public interface IFetchRequest<TQueried, TFetch> : IOrderedQueryable<TQueried> {}
Run Code Online (Sandbox Code Playgroud)

这模仿 NHibernate.Linq.INhFetchRequest<TQueried, TFetch>

然后定义一个实现:

public class FetchRequest<TQueried, TFetch> : IFetchRequest<TQueried, TFetch> {

    #region IEnumerable<TQueried> Members

    public IEnumerator<TQueried> GetEnumerator(){
        return NhFetchRequest.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return NhFetchRequest.GetEnumerator();
    }

    #endregion

    #region IQueryable Members

    public Type ElementType {
        get { return NhFetchRequest.ElementType; }
    }

    public System.Linq.Expressions.Expression Expression {
        get { return NhFetchRequest.Expression; }
    }

    public IQueryProvider Provider {
        get { return NhFetchRequest.Provider; }
    }

    #endregion

    public FetchRequest(INhFetchRequest<TQueried, TFetch> nhFetchRequest){
        NhFetchRequest = nhFetchRequest;
    }

    public INhFetchRequest<TQueried, TFetch> NhFetchRequest { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

这个只是拥有一个nHibernate实现,并将每个方法转发给该成员.

最后:

public static class EagerFetch {
/*
    replacing methods from NHibernate.Linq.EagerFetchingExtensionMethods
    private static INhFetchRequest<TOriginating, TRelated> CreateFluentFetchRequest<TOriginating, TRelated>(MethodInfo currentFetchMethod, IQueryable<TOriginating> query, LambdaExpression relatedObjectSelector);
    public static INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector);
    public static INhFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector);
    public static INhFetchRequest<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector);
    public static INhFetchRequest<TQueried, TRelated> ThenFetchMany<TQueried, TFetch, TRelated>(this INhFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector);
*/  
    public static IFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector){
        var fetch = EagerFetchingExtensionMethods.Fetch(query, relatedObjectSelector);
        return new FetchRequest<TOriginating, TRelated>(fetch);
    }

    public static IFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector){
        var fecth = EagerFetchingExtensionMethods.FetchMany(query, relatedObjectSelector);
        return new FetchRequest<TOriginating, TRelated>(fecth);
    }

    public static IFetchRequest<TQueried, TRelated> ThenFetch<TQueried, TFetch, TRelated>(this IFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, TRelated>> relatedObjectSelector){
        var impl = query as FetchRequest<TQueried, TFetch>;
        var fetch = EagerFetchingExtensionMethods.ThenFetch(impl.NhFetchRequest, relatedObjectSelector);
        return new FetchRequest<TQueried, TRelated>(fetch);
    }

    public static IFetchRequest<TQueried, TRelated> ThenFetchMany<TQueried, TFetch, TRelated>(this IFetchRequest<TQueried, TFetch> query, Expression<Func<TFetch, IEnumerable<TRelated>>> relatedObjectSelector){
        var impl = query as FetchRequest<TQueried, TFetch>;
        var fetch = EagerFetchingExtensionMethods.ThenFetchMany(impl.NhFetchRequest, relatedObjectSelector);
        return new FetchRequest<TQueried, TRelated>(fetch);
    }
}
Run Code Online (Sandbox Code Playgroud)