如何使用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);
}
答案 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