【问题标题】:NHIbernate DataReader Equivalent?NHIbernate DataReader 等效?
【发布时间】:2020-10-02 04:16:27
【问题描述】:

我对 NHibernate 有点陌生,所以这个问题可能很简单。无论如何,我正在替换一个使用 ADO.NET 的工作项目,该项目现在将使用 NHibernate(With LinqToNhibernate)。到目前为止,这工作得很好,但是我遇到了一个需要搜索大量数据(大约 200,000 条记录,使用非常特定的算法(对于 LINQ 来说太复杂)测试每条记录)的函数,如果它符合我想要将其添加到结果列表中的条件。在 ADO.NET 中,我使用了数据读取器,因此我不必将所有结果加载到内存中。在 NHibernate 中是否有等效的方法来执行此操作?懒惰的人会这样做吗?加载用于此?谢谢!

【问题讨论】:

  • 复杂算法是什么?
  • 好吧,我不能发布代码,因为它是为企业服务的。本质上,它会查看 VIN(车辆识别号),测试它是否与基于字符串 (VIN) 中的特定位置将数字与特定车辆型号联系起来的表匹配。如果您不了解 VIN 对我所居住的州的作用,我无法真正解释它。
  • 是 .Net 代码还是 SQL 或两者兼而有之?
  • 这个是不是需要做很多报告操作?
  • Paco,有一些 SQL 最初只是稍微缩小了结果范围(例如,查看代码的某个部分并意识到我需要拉出所有法拉利、福特等。 ) 其中大部分只是 .NET 代码,它挑选字符串并尝试根据结果中的每条记录对其应用匹配项(例如,此字符是否匹配,下一个字符是否为通配符——好的,跳过它等)。

标签: nhibernate


【解决方案1】:

好吧,根据我对 ISession.CreateQuery 的记忆,您可以返回一个列表或一个可枚举。 List 会将它们全部加载到内存中(我相信)。 IEnumerable 将向服务器发出一条语句以从服务器检索所有 Id。每次遍历 ienumerable 时,它​​都会检查缓存,如果它不在缓存中,它会发出数据库调用来检索信息。

它们都不是你想要的。您要么使用大量内存,要么锤击数据库。

听起来您确实在尝试进行某种 ETL 操作。最好的办法是保留一些专门的代码来处理这种情况。

如果您坚持使用 NHibernate,我只会在可管理的块中对结果进行分页并在此处使用无状态会话:

http://davybrion.com/blog/2008/10/bulk-data-operations-with-nhibernates-stateless-sessions/

【讨论】:

  • 嘿,对不起——我忘了​​说我正在使用 LinqToNhibernate,所以我不使用查询(除了 Linq)。
  • 如果您将所有数据访问抽象到存储库中,我看不出使用 HQL 或 ICriteria 有什么问题。 AFAIK,LinqToNhibernate 还不是很成熟......
  • Frederik,我没有使用存储库模式,因为我还没有发现需要它。现在最简单的是管理业务层中的会话和查询。是的,我在 LinqToNhibernate 中发现了一些需要解决的限制(没有连接),但到目前为止效果很好。
  • 在 linq 中,您仍然可以执行 Take - Skip 操作以进行分页以处理您的内存。
  • 谢谢!我认为 Take 操作可能会起作用——我记得现在阅读了那个扩展。
【解决方案2】:

您可能知道,在使用 NHibernate 时,您必须以完全不同的方式处理数据。您不再像在 ADO.NET 中那样使用来自数据库的“原始数据”;相反,您正在使用面向数据的 OO 视图。

您不查询 NHibernate 中的数据库/表,而是查询您的实体。

我认为您的问题的解决方案可以在预测中找到。 通过投影,您可以在 NHibernate 中创建查询(使用 HQL 或 ICriteria API)。
但是,在执行查询之前,您可以通过投影指定您感兴趣的属性。
NHibernate 然后将执行一个只检索这些属性的查询。这也意味着返回的并不是真正的实体。它是一个返回的 DTO。

因此,您必须创建一个充当此“DTO”的类。它只有你感兴趣的属性,你还必须“导入”这个类,以便 NHibernate 知道它。

不久前,我在 SO 上解释了如何使用投影。可以找到here

【讨论】:

    【解决方案3】:

    对于像您所拥有的那样的边缘情况向后兼容性,您只需在其上创建一个DbCommandExecuteReader,就像这样

            using (var session = this.SessionFactory.OpenSession())
            {
                using (DbCommand command = session.Connection.CreateCommand())
                {
                    command.Connection = session.Connection;
                    command.CommandText = queryString;
    
                    Command.CommandTimeout = 60 * 100;
                    Command.CommandType = CommandType.Text;
    
                    var parameter = Command.CreateParameter();
                    parameter.ParameterName = "@ParamName";
                    parameter.Value = whatever_value;
                    Command.Parameters.Add(parameter);
    
    
                    var dataReader = Command.ExecuteReader(CommandBehavior.CloseConnection);
    
                    // TODO: Enumerate your data reader
                }
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      相关资源
      最近更新 更多