在一个表中查找行,并使用 NHibernate 将其移动到第二个表中
本文关键字:NHibernate 第二个 移动 一个 查找 | 更新日期: 2024-11-06 15:06:00
>我有一个SQL Server 2014数据库,其中包含一个名为Positions
的包含大量数据的表(全速可能是数百万行)。Id
是主键,此表上没有其他键或外部关系。
假设我有一个n
元素的列表,例如[{a1, b1, c1}, ... , {an; bn; cn}]
,我必须在Positions
表内进行搜索并获取所有匹配的行:
(columnA == a1 && columnB == b1 && columnC == c1)
OR
(columnA == an && columnB == bn && columnC == cn)
此查询可能会产生 0 到 n 行(即没有两行具有相同的{a, b c}
)生成的行应从Partitions
表中删除并插入到名为 DeletedPositions
的第二个表中,并且一切都应以原子方式完成。
中执行此操作,现在因为我不知道NHibernate:
- 我有用于此类操作的设施吗?
- 我应该使用 NHibernate 还是批处理 SQL 命令会执行得更好?
- 如何确保移动所有(或不移动)行?
这完成了工作,我如何改进它以制作相关的插入?
var configuration = new Configuration().DataBaseIntegration(db =>
{
db.ConnectionString = @"Server=***;Database=***;Uid=***;Pwd=***;";
db.Dialect<MsSql2008Dialect>();
db.BatchSize = 700;
});
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());
HbmMapping mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
configuration.AddMapping(mapping);
var sessionFactory = configuration.BuildSessionFactory();
IList<PositionDTO> p = null;
using (IStatelessSession statelessSession = sessionFactory.OpenStatelessSession()) {
p = statelessSession
.QueryOver<PositionDTO>()
.Where(Restrictions.On<PositionDTO>(y => y.ColumnA).IsIn(a))
.And(Restrictions.On<PositionDTO>(y => y.ColumnB).IsIn(b))
.And(Restrictions.On<PositionDTO>(y => y.ColumnC).IsIn(c))
.List<PositionDTO>();
using (ITransaction transaction = statelessSession.BeginTransaction())
{
foreach (var t in p)
{
statelessSession.Delete(t);
}
transaction.Commit();
}
}
- 使用
- NHibernate 时,使用具有足够隔离级别的事务,该事务跨越 HQL
insert
查询,后跟delete
查询。最好将这些查询命名为在会话工厂引导程序中进行验证,但如果必须动态构造它,请使用"内置代码"HQL 字符串。基本部分示例:
<!-- put that in your .hbm.xml mappings -->
<query name="yourInsertsQuery">
insert into YourTarget
(
prop1, prop2, prop3
)
select s.propA, sre.propB, ot.propC
from YourSource s
inner join s.SomeRelatedEntities sre
with sre.anythingOnWhichYouHaveAdditionalRestrictions = :someParam
left join s.OtherThings ot
where s.someProp = :someOtherParam
and o.someBooleanCol = false
</query>
// If you required such a high isolation level, so be it, but try
// avoiding it otherwise.
var tran = session.BeginTransaction(IsolationLevel.Serializable);
try
{
session.GetNamedQuery("yourInsertsQuery")
.SetParameter("someParam", someValue)
.SetParameter("someOtherParam", someOtherValue)
.ExecuteUpdate();
session.GetNamedQuery("yourDeleteQuery")
.SetParameter("someParam", someValue)
.SetParameter("someOtherParam", someOtherValue)
.ExecuteUpdate();
tran.Commit()
}
catch
{
try
{
tran.Rollback();
}
catch(Exception rollbackEx)
{
// better log rollbackEx then swallow it (no throw in this nested catch)
// to let original trouble bubble up.
}
// Let original failure bubble up
throw;
}
- 编辑:实际上,使用SQL不会有太大的性能差异。我正在考虑将 SQL
merge
用于将两个操作合二为一,但这在您的情况下不可行,因为插入目标与删除目标不同。
由于从应用到数据库以处理操作的两个调用之间引入了网络延迟,因此你将有一些差异。这将导致事务持续时间稍长,从而可能阻止其他应用程序调用更长。SQL 批处理将避免插入和删除之间的这种额外的网络延迟。
如果你想要一个 sql 存储过程,你可以使用映射中定义的命名 sql 查询来调用它,如果你愿意:只需使用<sql-query>
,并使用参数将 SQLexec
放入其中,如 hql 示例中所示。 - 将您的处理封装在单个事务中。