将 NHibernate 开放会话合并到 DB(耦合 NHibernate 和 DB 会话)

Posted

技术标签:

【中文标题】将 NHibernate 开放会话合并到 DB(耦合 NHibernate 和 DB 会话)【英文标题】:Consolidating NHibernate open sessions to the DB (coupling NHibernate and DB sessions) 【发布时间】:2010-01-25 14:40:54 【问题描述】:

我们将 NHibernate 用于 ORM,在程序的初始化阶段,我们需要从数据库中加载一些 T 类的许多实例。

在我们的应用程序中,提取所有这些实例的以下代码需要很长时间:

public IList<T> GetAllWithoutTransaction()

    using (ISession session = GetSession())
    
        IList<T> entities = session
            .CreateCriteria(typeof(T))
            .List<T>();
        return entities;
        
    

使用 NHibernate 日志,我发现框架使用的实际 SQL 查询是:


    Load a bunch of rows from a few tables in the DB (one SELECT statement).

    for each instance of class T
    
        Load all the data for this instance of class T from the abovementioned rows 
        (3 SELECT statements).
    

3 个 select 语句是耦合的,即第二个依赖于第一个,第三个依赖于前两个。 如您所见,SELECT 语句的数量以百万计,这给我们带来了巨大的开销,这直接来自对数据库的所有调用(每个调用都需要“打开数据库会话”、“关闭数据库会话”…… ),即使我们使用的是单个 NHibernate 会话。

我的问题是: 我想以某种方式将所有这些 SELECT 语句合并到一个大的 SELECT 语句中。我们没有运行多线程,也没有在初始化阶段以任何方式更改数据库。

这样做的一种方法是定义我自己的对象并使用 NHibernate 对其进行映射,这将快速加载并在一个查询中加载所有内容,但这需要我们自己实现这些语句中使用的连接操作,并且更糟糕的是 - 破坏了 ORM 抽象。 有没有办法通过一些配置来做到这一点?

谢谢大家!

【问题讨论】:

你试过玩批量大小吗? 如果你真的是 NHibernate 新手,你可能想看看 nhibernate profiler。 NHibernate 不适用于批处理。我对 99% 的查询使用 NHibernate,但对于批处理,ETL 或普通 sql 可能会更好。 【参考方案1】:

这被称为SELECT N+1 problem。您需要决定将连接放置在哪里 (FetchMode.Eager)

【讨论】:

【参考方案2】:

如果您可以在 SQL 中将查询编写为单个查询,则可以让 NHibernate 将其作为单个查询执行(通常不会破坏抽象)。

当您在这种情况下真正想要的是急切加载时,您似乎有一些关系/类设置为延迟加载。

在 NHibernate 文档中有很多很好的信息。您可能想从这里开始:

http://www.nhforge.org/doc/nh/en/index.html#performance-fetching

【讨论】:

谢谢大家!我还没有找到解决方案,但我正在朝着毛里西奥回答的方向寻求解决方案。到了那里我会通知你的。 我终于设法将 NHibernate 配置为使用 fetch="join" 和所有这些在一个查询中加载所有内容。一个主要问题是我有循环依赖,类 T 有一个类型为 T 的实例列表,我需要定义一个中间映射以使其工作。再次感谢您的帮助!

以上是关于将 NHibernate 开放会话合并到 DB(耦合 NHibernate 和 DB 会话)的主要内容,如果未能解决你的问题,请参考以下文章

如何 NHibernate 将多个类映射到同一个表

WPF MVVM 中的 NHibernate 会话

使用 IIS 7 的 NHibernate 会话

事务如何在 nhibernate 中工作?

在控制器和存储库的上下文中很难使用 Nhibernate 会话

在 Nhibernate 中分离和附加代理