不清楚的NHibernate 3.2散装插入/HQL问题
本文关键字:插入 HQL 问题 散装 NHibernate 不清楚 | 更新日期: 2023-09-27 18:30:07
我需要根据用户传入的一组日期,将事件记录"批量"插入数据库。
我的事件实体具有StartTime属性和StopTime属性。Event实体是我的应用程序中的核心实体,因此有许多集合和实体引用与之相关。它是一个沉重的实体。
所以,我最初的代码让我循环浏览日期,并做这样的事情:
Session.Save(new Event {StartTime=startdate, StopTime=endDate});
然而,这并没有很好地扩展,当插入几百个日期时,我们感觉到了性能。
因此,我曾想过将所有日期插入一个临时表中,但我不知道如何使用HQL来实现这一点。
因此,我的下一个想法是将所有日期作为子查询包括在内,这使我最接近。这是一种方法:
var hql = "INSERT INTO Event (Code, Comment, Description, Status, StartTime, StopTime)
SELECT ev.Code, ev.Comment, ev.Description, ev.Status, Dates.SDate, Dates.EDate
FROM Event ev,
(
SELECT '1/2/2012 3:00:00 PM' as SDate, '1/2/2012 6:00:00 PM' as EDate
UNION ALL SELECT '1/3/2012 3:00:00 PM', '1/3/2012 6:00:00 PM'
UNION ALL SELECT '1/4/2012 3:00:00 PM', '1/4/2012 6:00:00 PM'
) as Dates
WHERE ev.Id = :sourceEventId";
Session.CreateQuery(hql).SetInt32("sourceEventId", @event.Id).ExecuteUpdate();
但是hql失败了,错误代码非常模糊。我在网上的研究告诉我hql还不支持UNION子句。
现在,我将这种方法重写为SQL,并通过Session.CreateSQLQuery()执行,效果非常好。但我不想将其作为SQL运行。无论如何,这违背了与NHibernate合作的目的。
有没有其他方法可以使用HQL(或任何其他NHibernate技术)来解决这个问题?
非常感谢您的帮助!
更新
我忘了提到这是一个遗留的SQL Server数据库(我在sqlite上运行单元测试),并且所有实体都使用SQL的Identity列生成它们的id。因此,任何批处理尝试都会失败。
正如我在下面的评论中所解释的,我还尝试了无状态会话方法。NHibernate会失败地告诉我,我需要先保存我所有的懒惰加载实体。我通过删除这些映射暂时解决了这个问题,它确实起到了作用,而且比常规会话更快。但我最终还是不得不一次插入一个实体。
尝试使用无状态会话而不是会话
using (var session = sessionFactory.OpenStatelessSession())
using (var tx = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
session.Insert(yourObjects[i]);
}
tx.Commit();
}
这个链接也有助于
此外,您可以使用ADO.net SqlBulkCopy而不是无状态会话,请检查此项。
这个怎么样?
var sdates = new []{ "1/2/2012 3:00:00 PM", "1/3/2012 3:00:00 PM", "1/4/2012 3:00:00 PM" };
var edates = new []{ "1/2/2012 6:00:00 PM", "1/3/2012 6:00:00 PM", "1/4/2012 6:00:00 PM" };
var hql = "INSERT INTO Event (Code, Comment, Description, Status, StartTime, StopTime)
SELECT ev.Code, ev.Comment, ev.Description, ev.Status, :sdate, :edate
FROM Event ev
WHERE ev.Id = :sourceEventId";
for(var i=0;i<sdates.Length;i++)
{
Session.CreateQuery(hql).SetInt32("sourceEventId", @event.Id)
.SetString("sdate", sdates[i])
.SetString("edate", edates[i])
.ExecuteUpdate();
}
也许您需要使用DateTime而不是字符串,并对代码进行一些调整,但这是一个想法。基本上,你将执行三个命令,而不是一个,但也不是n+1(这是你的缩放问题,对吧?)
希望能有所帮助。