模糊的NHibernate 3.2批量插入/ HQL问题

时间:2012-04-04 23:14:13

标签: c# .net nhibernate hql bulkinsert

我要求根据用户传入的一组日期,将事件记录的“批量”插入到数据库中。

我的事件实体有一个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技术)来解决这个问题?

非常感谢任何帮助!

更新

  1. 我忘了提到这是一个遗留的SQL Server数据库(我在sqlite上运行单元测试),并且所有实体都使用SQL的Identity列生成它们的id。所以批量失败的任何尝试。

  2. 正如我在下面的评论中解释的那样,我也尝试过无状态会话方法。 NHibernate会告诉我我需要先保存所有延迟加载的实体。我通过删除这些映射暂时解决了这个问题,它确实有效,而且比常规会话更快。但我仍然不得不一次一个地插入每个实体。

2 个答案:

答案 0 :(得分:1)

尝试使用无状态会话而不是会话

using (var session = sessionFactory.OpenStatelessSession())
using (var tx = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
    session.Insert(yourObjects[i]);
}
tx.Commit();
}

this link is also helpful

此外,您可以使用ADO.net SqlBulkCopy而不是无状态会话check this

答案 1 :(得分:0)

这个怎么样?

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(那是你的scalation问题,对吗?)

希望它有所帮助。