c# - NHibernate OutOfMemoryException 查询大字节 []

标签 c# nhibernate fluent-nhibernate

我正在尝试使用 Fluent NHibernate 迁移需要“处理”部分数据库的数据库。源数据库是一个 MS Access 数据库,我当前使用的表是一个带有 OLE 对象字段的表。目标数据库是 MS SQL Server Express 数据库。

在实体中,我只是将这个字段定义为 byte[] 但是在加载时,即使只是为单个记录加载单个字段,我也会遇到 System.OutOfMemoryException

byte[] test = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == 5590).Select(x => x.FileData).SingleOrDefault<byte[]>();

然后我尝试实现 blob type listed here但是现在运行时我收到错误:

"Unable to cast object of type 'System.Byte[]' to type 'TestProg.DatabaseConverter.Entities.Blob'."}

我无法想象 Ole 对象大于 100mb 但无法检查。有什么好的方法可以使用 Fluent NHibernate 将其从一个数据库中复制出来并将其保存到另一个数据库中,还是我需要查看其他选项?

我处理这些的正常循环是:

IList<Entities.Access.Revision> result;
IList<int> recordIds = aSession.Query<Entities.Access.Revision>().Select(x => x.Id).ToList<int>();

foreach (int recordId in recordIds)
{
  result = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == recordId).ToList<Entities.Access.Revision>();
  Save(sqlDb, result);
}

保存功能只是将属性从一个实体复制到另一个实体,对于某些实体,它用于操作数据或向用户提供与数据问题相关的反馈。我正在为两个数据库使用无状态 session 。

--

从进一步测试来看,它似乎卡在上面的物体大约有 60-70mb。我目前正在测试使用 GetBytes 使用 OleDbDataReader 抓取数据。

--

更新(11 月 24 日):我还没有找到使它与 NHibernate 一起工作的方法。我确实使用了常规的 db 命令对象。我已经将我制作的功能代码放在下面,供任何好奇的人找到。这是来 self 的数据库转换器的代码,因此前缀为“a”的对象是访问数据库对象,“s”是 sql 对象。

public void MigrateBinaryField(int id, string tableName, string fieldName)
{
   var aCmd = new OleDbCommand(String.Format(@"SELECT ID, {0} FROM {1} WHERE ID = {2}", fieldName, tableName, id), aConn);

   using (var reader = aCmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess))
   {
       while (reader.Read())
       {
           if (reader[fieldName] == DBNull.Value)
               return;

           long read = 0;
           long offset = 0;

           // Can't .WRITE a NULL column so need to set an initial value
           var sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1} = @data WHERE OldId = @OldId", tableName, fieldName), sConn);
           sCmd.Parameters.AddWithValue("@data", new byte[0]);
           sCmd.Parameters.AddWithValue("@OldId", id);
           sCmd.ExecuteNonQuery();

           // Incrementally store binary field to avoid OutOfMemoryException from having entire field loaded in memory
           sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1}.WRITE(@data, @offset, @len) WHERE OldId = @OldId", tableName, fieldName), sConn);
           while ((read = reader.GetBytes(reader.GetOrdinal(fieldName), offset, buffer, 0, buffer.Length)) > 0)
           {
               sCmd.Parameters.Clear();
               sCmd.Parameters.AddWithValue("@data", buffer);
               sCmd.Parameters.AddWithValue("@offset", offset);
               sCmd.Parameters.AddWithValue("@len", read);
               sCmd.Parameters.AddWithValue("@OldId", id);

               sCmd.ExecuteNonQuery();

               offset += read;
           }                    
       }
   }
}

最佳答案

这听起来像是我在其他框架之上使用 .NET 时看到的结果。

NHibernate 下 ADO.NET 下的 native 数据库驱动程序(此处有意使用两个“下部”)将需要一个固定的目标内存块,当驱动程序填充它时,该内存块不能在内存中移动。由于 .NET 垃圾收集器可以在单独的线程上随机移动内存块以压缩堆,NHibernate 的底层 .NET 数据库层必须创建一个非托管内存块来接收数据,这有效地使内存量翻倍需要加载记录。

此外,我还没有验证下一点,但 NHibernate 应该尝试缓存记录 block ,因为它绕过了一些关系数据库查询操作。这允许 NHibernate 发出更少的数据库请求,这对于较小的记录大小是最佳的,但一次需要许多记录(包括许多 blob)以适应内存。

作为解决问题的第一步,确保该进程确实使机器内存不足(或者如果它是 32 位,确保它达到 2GB 限制)。如果是这样,尝试确定基线——如果它正在处理具有各种 blob 大小的记录,它使用的最小和最大内存是多少?由此,您可以估计该大记录(或包含该记录的缓存 block !)需要多少内存。

64 位和更多物理内存可能是一种强力解决方案,如果您还没有运行 64 位,并且甚至可以选择更大的硬件。

另一种可能的解决方案是检查 NHibernate 是否具有关于它如何缓存数据的可配置设置或属性。例如,检查您是否可以设置一个属性来限制一次加载多少条记录,或者告诉它以字节为单位将其缓存限制为特定大小。

一个更有效的解决方案是将 ADO.NET 代码用于 blob;这可能是最好的解决方案,特别是如果您希望得到比这个特定的 60-70MB blob 更大的 blob。 MS Access 通常会允许多个只读连接,所以只要 NHibernate 没有将数据库设置为阻止其他连接,这应该就可以工作。

关于c# - NHibernate OutOfMemoryException 查询大字节 [],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33392921/

相关文章:

c# - 如何将类属性的值设置为插入到数据库时另一个类的生成的 id 值?

c# - 流利的 NHibernate 多对多

nhibernate - HBM 映射图像/二进制

fluent-nhibernate - Fluent nHibernate 表中没有标识列

c# - 如何在 MVC4 中获取第二个下拉列表的值?

c# - 在哪里记录异常?

c# - 授权策略的依赖注入(inject)

c# - NHIbernate:Restriction.In 和 Restriction.InG 的区别

c# - 在 Fluent NHibernate 中创建复合索引?

nhibernate - 如何在 Fluent NHibernate 中建模此对象层次结构而不违反 DDD 原则?