首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Nhibernate .Fetch调用在模拟会话上失败

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

Stack Overflow用户
提问于 2015-10-23 00:43:41
回答 3查看 1.4K关注 0票数 7

我喜欢NHibernate (和NHibernate.Linq)。我不会过早地进行优化,但有时我会遇到非常糟糕的N+1问题。推荐的N+1修复方法是使用NH的Fetch扩展方法。

当我创建ISession的模拟时,问题就出现了。我将创建一个List<User>,并将我的模拟设置为每当有人调用_session.Query<User>()时返回该列表。当我向查询添加Fetch调用(即_session.Query<User>().Fetch(u => u.Address) )时,我收到以下错误消息:

代码语言:javascript
复制
There is no method 'Fetch' on type 'NHibernate.Linq.EagerFetchingExtensionMethods' 
that matches the specified arguments

NHibernate的fetch接受一个普通的旧IQueryable<T>,但尝试将其转换为特定的NH实现,如果不能,则会失败。

我真的希望Fetch在非NH实现(即列表)上被调用时不会出错,并被忽略,这样我仍然可以在单元测试中使用它。帮助!

EN

Stack Overflow用户

发布于 2015-10-23 00:43:41

好吧,我试着自己实现这一点,但谢天谢地,我找到了一个已经做了跑腿工作的人。

http://mycodinglife.blog.com/2013/06/10/fetch-good-boy-now-play-nice-with-my-unit-tests/#

您唯一需要做的就是调用EagerlyFetch,而不仅仅是Fetch

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

代码语言:javascript
复制
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);
        }
    }
}
票数 5
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33286244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档