【问题标题】:NHibernate 3 or 4 Equivalent to Entity Framework IncludeNHibernate 3 或 4 等效于实体框架包括
【发布时间】:2016-05-20 20:30:36
【问题描述】:

NHibernate 3 或 4 是否具有与实体框架的“包含”方法等效的方法,该方法采用 字符串参数 而不是 llambda?我想在 NHibernate 中做这样的事情:

Contact contact =
        context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails")
        .FirstOrDefault();

我从this post 发现了这段代码,它在一个很酷的循环中使用“Fetch”,但这仅处理作为主对象的第一级子对象的对象,而上面的 EF 代码下降了 2 个级别不需要强类型的 llambda。

public IQueryable<T> All<T>(params Expression<Func<T, Object>> [] fetchPaths)
{
    var queryable = this.session.Query<T>();

    foreach (var fetchPath in fetchPaths)
    {
        queryable = queryable.Fetch(fetchPath);
    }

    return queryable;
}

【问题讨论】:

  • 这里需要HQL吗?有没有人写过一个简洁的方法来生成适当的 HQL 来处理像 .Include("SalesOrderHeaders.SalesOrderDetails") 这样的场景?

标签: c# entity-framework linq nhibernate fluent-nhibernate


【解决方案1】:

NHibernate 有第二种方法,称为 ThenFetch。你必须写

this.session.Query<T>()
            .Fetch(x => x.Property)
            .ThenFetch(x => x.SubProperty);

【讨论】:

  • 这将适用于特定查询,但我正在寻找一种类似于我帖子中的“All”方法的基本实现,它将处理任何类型的查询。 “包含”的字符串参数非常好,因为这样您就不必担心 Fetch/ThenFetch llambda 语法的强类型特性。
  • 我认为您不会找到实际的替代方案。我会编写一个解析器来自动构建这些表达式树。但是,我同意你的看法,这很麻烦......
【解决方案2】:

似乎有几个选项可以解决我的问题。

方案一:动态构建HQL的形式:

from Contacts t0
left join fetch t0.SalesOrderHeaders t1
left join fetch t1.SalesOrderDetails t2

选项 2: 使用 NHibernate 的 ICriteria.SetFetchMode。这可以处理基于字符串的连接,这非常有用,并且比我的 HQL 方法更容易。这是我最终编写的代码(改编自 this post)。我希望它对其他人有帮助。 “GetPathsToUse”方法是我尝试让实体框架风格的包含路径。因此,如果我想提供“SalesOrderHeaders.SalesOrderDetails”作为唯一路径,该方法将首先在“SalesOrderHeaders.SalesOrderDetails”之前添加“SalesOrderHeaders”,这样NH 会很高兴。

// This also uses ICriteria, but adds some logic to auto-handle paths to reduce the number of paths needed to pass in to match how 
        // EntityFramework works e.g. if one path is passed in for OrderInputs.Input, this method will call SetFetchMode twice, once for OrderInputs and again for OrderInputs.Input
        public T GetByIdSetFetchModeEFStyle(Guid id, ISession session, params string[] includePaths)
        {   
            ICriteria criteria = session.CreateCriteria<T>();

            if (includePaths != null && includePaths.Length > 0)
            {
                // NHibernate requires paths to be supplied in order.  So if a path "OrderInputs.Input" is supplied, we must make 
                // 2 separate calls to SetFetchMode, the first with "OrderInputs", and the second with "OrderInputs.Input".
                // EntityFramework handles this for us, but NHibernate requires things to be different.
                List<string> pathsToUse = this.GetPathsToUse(includePaths);

                foreach (string path in pathsToUse)
                {
                    criteria.SetFetchMode(path, FetchMode.Eager);
                }
            }

            return criteria
                // prevent duplicates in the results
                .SetResultTransformer(Transformers.DistinctRootEntity)
                .Add(Restrictions.Eq(typeof(T).Name + "Id", id)).UniqueResult<T>();
        }

        private List<string> GetPathsToUse(string[] includePaths)
        {
            var nhPaths = new List<string>();
            foreach (string path in includePaths)
            {
                if (!path.Contains(".") && !nhPaths.Contains(path))
                {
                    // There is no dot in the path - just add it if it hasn't been added already
                    nhPaths.Add(path);
                }
                else
                {
                    // We have a dot e.g. OrderInputs.Input.  We need to add "OrderInputs" before "OrderInputs.Input"
                    string[] pathParts = path.Split(".".ToCharArray());

                    // Add any missing ancestors of the current path prior to adding the path
                    for (int p = 1; p <= pathParts.Length; p++)
                    {
                        string requiredPath = string.Join(".", pathParts.Take(p).ToArray());
                        if (!nhPaths.Contains(requiredPath))
                        {
                            nhPaths.Add(requiredPath);
                        }
                    }
                }
            }
            return nhPaths;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    相关资源
    最近更新 更多