如何在不导致OutOfMemoryException的情况下保存大型nhibernate集合

时间:2010-06-14 23:46:48

标签: c# nhibernate

如何使用NHibernate保存大型集合,其中的元素超出了进程允许的内存量?

我正在尝试使用具有大量屏幕截图的nhibernate保存Video对象(请参阅下面的代码)。每个屏幕截图都包含一个byte [],因此在nhibernate尝试一次保存10,000个左右的记录之后,会抛出OutOfMemoryException。通常情况下,我会尝试分解保存并在每500个左右的记录后刷新会话,但在这种情况下,我需要保存集合,因为它会自动为我保存SortOrder和VideoId(没有屏幕截图必须知道它是视频的一部分)。鉴于我的情况,最好的方法是什么?有没有办法打破这个保存而不强迫屏幕截图知道其父视频?

供您参考,以下是我创建的简单示例中的代码:

public class Video
{
    public long Id { get; set; }
    public string Name { get; set; }

    public Video()
    {
        Screenshots = new ArrayList();
    }

    public IList Screenshots { get; set; }
}

public class Screenshot
{
    public long Id { get; set; }
    public byte[] Data { get; set; }
}

并映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SavingScreenshotsTrial"
                   namespace="SavingScreenshotsTrial"
                   default-access="property">
  <class name="Screenshot"
         lazy="false">
    <id name="Id"
        type="Int64">
      <generator class="hilo"/>
    </id>

    <property name="Data" column="Data" type="BinaryBlob" length="2147483647" not-null="true" />
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="SavingScreenshotsTrial"
                   namespace="SavingScreenshotsTrial" >
  <class name="Video"
         lazy="false"
         table="Video"
         discriminator-value="0"
         abstract="true">
    <id name="Id"
        type="Int64"
        access="property">
      <generator class="hilo"/>
    </id>
    <property name="Name" />
    <list name="Screenshots"
          cascade="all-delete-orphan"
          lazy="false">
      <key column="VideoId" />
      <index column="SortOrder" />
      <one-to-many class="Screenshot" />
    </list>
  </class>
</hibernate-mapping>

当我尝试使用10000个屏幕截图保存视频时,会抛出OutOfMemoryException。这是我正在使用的代码:

        using (var session = CreateSession())
        {
            Video video = new Video();
            for (int i = 0; i < 10000; i++)
            {
                video.Screenshots.Add(new Screenshot() {Data = camera.TakeScreenshot(resolution)});
            }
            session.SaveOrUpdate(video);
        }

3 个答案:

答案 0 :(得分:2)

出于这个原因,我们通常将子实体引用为父实体而不是反之亦然。

答案 1 :(得分:0)

使用AbstractType和IParameterizedType创建自定义类型,这些类型位于NHibernate.Type命名空间中。使用无状态会话并提供批量大小。

答案 2 :(得分:0)

nhibernate文档的第13章处理了此问题。

“使用NHibernate在数据库中插入100000行的天真的方法可能看起来像这样:

using (ISession session = sessionFactory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
for (int i = 0; i < 100000; i++)
{
Customer customer = new Customer(.....);
session.Save(customer);
}
tx.Commit();
}

这将在第50 000行附近出现OutOfMemoryException [...]“

要恢复...通过设置以下属性,该解决方案适用于批处理大小且没有二级缓存:

批量大小:

  

adonet.batch_size 20

二级缓存:

  

cache.use_second_level_cache false

应该解决OutOfMemoryException。

更多资料,请参见文档参考:http://nhibernate.info/previous-doc/v5.0/single/nhibernate_reference.pdf