Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Nhibernate.Fetch调用在模拟会话上失败_C#_Unit Testing_Nhibernate_Linq To Nhibernate - Fatal编程技术网

C# Nhibernate.Fetch调用在模拟会话上失败

C# Nhibernate.Fetch调用在模拟会话上失败,c#,unit-testing,nhibernate,linq-to-nhibernate,C#,Unit Testing,Nhibernate,Linq To Nhibernate,我爱NHibernate(和NHibernate.Linq)。我不会过早地进行优化,但有时会遇到非常严重的N+1问题。对于N+1,建议使用NH的Fetch扩展方法 当我创建会话的模拟时,问题就出现了。我将创建一个列表,并将我的mock设置为在有人调用\u session.Query()时返回列表。当我向查询(即\u session.query().Fetch(u=>u.Address)添加Fetch调用时,我会收到以下错误消息: There is no method 'Fetch' on typ

我爱NHibernate(和NHibernate.Linq)。我不会过早地进行优化,但有时会遇到非常严重的N+1问题。对于N+1,建议使用NH的
Fetch
扩展方法

当我创建
会话的模拟时,问题就出现了。我将创建一个
列表
,并将我的mock设置为在有人调用
\u session.Query()
时返回列表。当我向查询(即
\u session.query().Fetch(u=>u.Address)
添加
Fetch
调用时,我会收到以下错误消息:

There is no method 'Fetch' on type 'NHibernate.Linq.EagerFetchingExtensionMethods' 
that matches the specified arguments
NHibernate的fetch接受普通的
IQueryable
,但尝试将其转换为特定的NH实现,如果不能,则失败


如果在非NH实现(即列表)上调用它,我真的希望
Fetch
不会出错,只是被忽略了,这样我仍然可以在单元测试中使用它。救命!

好吧,我自己尝试过实现它,但感谢上帝,我找到了一个已经做了这些工作的人

你唯一需要做的事情就是急切地调用
Fetch
,而不仅仅是
Fetch

我复制了下面的相关代码,因为他的博客已经有相当数量的http 500错误和css问题。我认为它没有得到维护

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using NHibernate.Linq;
using Remotion.Linq;

namespace LittleFish.Persistence.Extensions
{
    /// <summary>
    /// Provides extension method wrappers for NHibernate methods 
    /// to allow consuming source code to avoid "using" NHibernate.
    /// </summary>
    public static class NHibernateExtensions
    {
        /// <summary>
        /// Eager-loads a projection of the specified queryable, 
        /// referencing a mapped child object.
        /// </summary>
        public static IFetchRequest<T, TRel> EagerlyFetch<T, TRel>(
            this IQueryable<T> queryable,
            Expression<Func<T, TRel>> expression)
        {
            if (queryable is QueryableBase<T>)
                return FetchHelper.Create(queryable.Fetch(expression));
            else
                return FetchHelper.CreateNonNH<T, TRel>(queryable);
        } 

        /// <summary>
        /// Eager-loads a second-level projection of the specified queryable, 
        /// referencing a mapped child of the first eager-loaded child.
        /// </summary>
        public static IFetchRequest<T, TRel2> ThenEagerlyFetch<T, TRel, TRel2>(
            this IFetchRequest<T, TRel> queryable,
            Expression<Func<TRel, TRel2>> expression)
        {
            if (queryable is QueryableFetchHelper<T, TRel>)
                return FetchHelper.CreateNonNH<T, TRel2>(queryable);
            else
                return FetchHelper.Create(queryable.ThenFetch(expression));
        } 

        /// <summary>
        /// Eager-loads a projection of the specified queryable, 
        /// referencing a mapped child object.
        /// </summary>
        public static IFetchRequest<T, TRel> EagerlyFetchMany<T, TRel>(
            this IQueryable<T> queryable,
            Expression<Func<T, IEnumerable<TRel>>> expression)
        {
            if(queryable is QueryableBase<T>)
                return FetchHelper.Create(queryable.FetchMany(expression));
            else
                return FetchHelper.CreateNonNH<T, TRel>(queryable);
        } 

        /// <summary>
        /// Eager-loads a second-level projection of the specified queryable, 
        /// referencing a mapped child of the first eager-loaded child.
        /// </summary>
        public static IFetchRequest<T, TRel2> ThenEagerlyFetchMany
            <T, TRel, TRel2>(
            this IFetchRequest<T, TRel> queryable,
            Expression<Func<TRel, IEnumerable<TRel2>>> expression)
        {
            if (queryable is QueryableFetchHelper<T, TRel>)
                return FetchHelper.CreateNonNH<T, TRel2>(queryable);
            else
                return FetchHelper.Create(queryable.ThenFetchMany(expression));
        }
    } 

    /// <summary>
    /// Provides a wrapper for NHibernate's FetchRequest interface, 
    /// so libraries that run eager-loaded queries don't have to reference 
    /// NHibernate assemblies.
    /// </summary>
    public interface IFetchRequest<TQuery, TFetch> :
        INhFetchRequest<TQuery, TFetch>
    {
    } 

    internal class NhFetchHelper<TQuery, TFetch> : IFetchRequest<TQuery, TFetch>
    {
        private readonly INhFetchRequest<TQuery, TFetch> realFetchRequest;

        //this is the real deal for NHibernate queries
        internal NhFetchHelper(INhFetchRequest<TQuery, TFetch> realFetchRequest)
        {
            this.realFetchRequest = realFetchRequest;
        } 

        public IEnumerator<TQuery> GetEnumerator()
        {
            return (realFetchRequest).GetEnumerator();
        } 

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (realFetchRequest).GetEnumerator();
        } 

        public Expression Expression
        {
            get { return (realFetchRequest).Expression; }
        } 

        public Type ElementType
        {
            get { return (realFetchRequest).ElementType; }
        } 

        public IQueryProvider Provider
        {
            get { return (realFetchRequest).Provider; }
        }
    } 

    internal class QueryableFetchHelper<TQuery, TFetch> :
        IFetchRequest<TQuery, TFetch>
    {
        private readonly IQueryable<TQuery> queryable;

        //for use against non-NH datastores
        internal QueryableFetchHelper(IQueryable<TQuery> queryable)
        {
            this.queryable = queryable;
        } 


        public IEnumerator<TQuery> GetEnumerator()
        {
            return (queryable).GetEnumerator();
        } 

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (queryable).GetEnumerator();
        } 


        public Expression Expression
        {
            get { return (queryable).Expression; }
        } 

        public Type ElementType
        {
            get { return (queryable).ElementType; }
        } 

        public IQueryProvider Provider
        {
            get { return (queryable).Provider; }
        }
    } 

    /// <summary>
    /// The static "front door" to FetchHelper, with generic factories allowing 
    /// generic type inference.
    /// </summary>
    internal static class FetchHelper
    {
        public static NhFetchHelper<TQuery, TFetch> Create<TQuery, TFetch>(
            INhFetchRequest<TQuery, TFetch> nhFetch)
        {
            return new NhFetchHelper<TQuery, TFetch>(nhFetch);
        } 

        public static NhFetchHelper<TQuery, TFetch> Create<TQuery, TFetch>(
            IFetchRequest<TQuery, TFetch> nhFetch)
        {
            return new NhFetchHelper<TQuery, TFetch>(nhFetch);
        } 

        public static IFetchRequest<TQuery, TRel> CreateNonNH<TQuery, TRel>(
            IQueryable<TQuery> queryable)
        {
            return new QueryableFetchHelper<TQuery, TRel>(queryable);
        }
    }
}
使用系统;
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
使用NHibernate.Linq;
使用Remotion.Linq;
命名空间LittleFish.Persistence.Extensions
{
/// 
///为NHibernate方法提供扩展方法包装
///允许使用源代码以避免“使用”NHibernate。
/// 
公共静态类NHibernateExtensions
{
/// 
///“渴望”加载指定可查询项的投影,
///引用映射的子对象。
/// 
公共静态IFetchRequest急切获取(
这是一个可以质疑的问题,
表达式(表达式)
{
if(queryable是QueryableBase)
返回FetchHelper.Create(queryable.Fetch(表达式));
其他的
返回FetchHelper.CreateNonNH(可查询);
} 
/// 
///“渴望”加载指定可查询项的第二级投影,
///引用第一个已加载子项的映射子项。
/// 
公共静态IFetchRequest然后立即获取(
这个请求是可查询的,
表达式(表达式)
{
if(queryable是QueryableFetchHelper)
返回FetchHelper.CreateNonNH(可查询);
其他的
返回FetchHelper.Create(queryable.ThenFetch(表达式));
} 
/// 
///“渴望”加载指定可查询项的投影,
///引用映射的子对象。
/// 
公共静态IFetchRequest急切地获取许多(
这是一个可以质疑的问题,
表达式(表达式)
{
if(queryable是QueryableBase)
返回FetchHelper.Create(queryable.FetchMany(表达式));
其他的
返回FetchHelper.CreateNonNH(可查询);
} 
/// 
///“渴望”加载指定可查询项的第二级投影,
///引用第一个已加载子项的映射子项。
/// 
公共静态IFetchRequest然后急切地获取许多
(
这个请求是可查询的,
表达式(表达式)
{
if(queryable是QueryableFetchHelper)
返回FetchHelper.CreateNonNH(可查询);
其他的
返回FetchHelper.Create(queryable.ThenFetchMany(表达式));
}
} 
/// 
///为NHibernate的FetchRequest接口提供包装,
///因此,运行即时加载查询的库不必引用
///NHibernate组件。
/// 
公共接口请求:
拒绝请求
{
} 
内部类NhFetchHelper:IFetchRequest
{
私有只读INhFetchRequest realFetchRequest;
//这是NHibernate查询的真正交易
内部NhFetchHelper(INhFetchRequest realFetchRequest)
{
this.realFetchRequest=realFetchRequest;
} 
公共IEnumerator GetEnumerator()
{
return(realFetchRequest).GetEnumerator();
} 
IEnumerator IEnumerable.GetEnumerator()
{
return(realFetchRequest).GetEnumerator();
} 
公开表达
{
获取{return(realFetchRequest).Expression;}
} 
公共类型ElementType
{
获取{return(realFetchRequest).ElementType;}
} 
公共IQueryProvider提供程序
{
获取{return(realFetchRequest).Provider;}
}
} 
内部类QueryableFetchHelper:
IFetchRequest
{
私有只读可查询;
//用于非NH数据存储
内部QueryableFetchHelper(IQueryable queryable)
{
this.queryable=queryable;
} 
公共IEnumerator GetEnumerator()
{
return(可查询).GetEnumerator();
} 
IEnumerator IEnumerable.GetEnumerator()
{
return(可查询).GetEnumerator();
} 
公开表达
{
获取{return(queryable).Expression;}
} 
公共类型ElementType
{
获取{return(queryable).ElementType;}
} 
公共IQueryProvider提供程序
{
获取{return(queryable).Provider;}
}
} 
/// 
///FetchHelper的静态“前门”,一般工厂允许
///泛型类型推断。
/// 
内部静态类FetchHelper
{
公共静态NhFetch
NHibernateExtensionsWrapper.Fetch(query, x => x.ChildTable).ToList();
public class NHibernateExtensionsWrapper : INHibernateExtensionsWrapper
{
    public INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(IQueryable<TOriginating> query,
        Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
    {
        return query.Fetch(relatedObjectSelector);
    }
}
public class NHibernateExtensionsWrapperMock : INHibernateExtensionsWrapper
{
    public INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector)
    {
        return (INhFetchRequest<TOriginating, TRelated>) new NhFetchRequest<TOriginating, TRelated>(query);
    }

    private class NhFetchRequest<TOriginating, TRelated> : INhFetchRequest<TOriginating, TRelated>
    {
        private readonly IQueryable<TOriginating> _query;

        public NhFetchRequest(IQueryable<TOriginating> query)
        {
            _query = query;
        }

        public IEnumerator<TOriginating> GetEnumerator()
        {
            return _query.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public Expression Expression => _query.Expression;

        public Type ElementType => _query.ElementType;

        public IQueryProvider Provider => _query.Provider;
    }
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
    //Don't overwrite if fetch wasn't the method being called
    if (!node.Method.Name.Equals(nameof(EagerFetchingExtensionMethods.Fetch))
        && !node.Method.Name.Equals(nameof(EagerFetchingExtensionMethods.FetchMany))
        && !node.Method.Name.Equals(nameof(EagerFetchingExtensionMethods.ThenFetch))
        && !node.Method.Name.Equals(nameof(EagerFetchingExtensionMethods.ThenFetchMany)))
    {
        return base.VisitMethodCall(node);
    }

    //Get the first argument to the Fetch call. This would be our IQueryable or an Expression which returns the IQueryable.
    var fetchInput = node.Arguments[0];

    Expression returnExpression;

    switch (fetchInput.NodeType)
    {
        case ExpressionType.Constant:
            //If the input was a constant we need to run it through VisitConstant to get the underlying queryable from NHibernateQueryableProxy if applicable
            returnExpression = VisitConstant((ConstantExpression)fetchInput);
            break;
        default:
            //For everything else just return the input to fetch
            //This is covers cases if we do something like .Where(x).Fetch(x), here fetchInput would be another method call
            returnExpression = fetchInput;
            break;
    }

    return returnExpression;
}