在我们的单元测试中,我们使用普通的 ADO.NET(DataTable、DataAdapter)来准备数据库。检查结果,而测试的组件本身在 NHibernate 2.1 下运行。.NET 版本是 3.5,SqlServer 版本是 2005。
数据库表将标识列作为主键。一些表应用而不是插入/更新触发器(这是由于向后兼容性,我无法更改)。触发器通常是这样工作的:
create trigger dbo.emp_insert
on dbo.emp
instead of insert
as
begin
set nocount on
insert into emp ...
select @@identity
end
ADO.NET DataAdapter 发出的插入语句(由瘦 ADO.NET 包装器即时生成)尝试将标识值检索回 DataRow:
exec sp_executesql N'
insert into emp (...) values (...);
select id, ... from emp where id = @@identity
'
但是 DataRow 的 id-Column 仍然为 0。当我暂时删除触发器时,它工作正常 - id-Column 然后保存数据库设置的标识值。
另一方面,NHibernate 使用这种插入语句:
exec sp_executesql N'
insert into emp (...) values (...);
select scope_identity()
'
这行得通,NHibernate POCO 在刷新后立即正确设置了其 id 属性。这对我来说似乎有点违反直觉,因为我希望触发器在不同的范围内运行,因此 @@identity 应该比 scope_identity() 更适合。
所以我认为没问题,我也会在 ADO.NET 下应用 scope_identity() 而不是 @@identity。但这没有任何效果,DataRow 值仍然没有相应地更新。
现在最好的部分是:当我将这两个语句从 SqlServer 分析器复制并粘贴到 Management Studio 查询中(包括“exec sp_executesql”)并在那里运行它们时,结果似乎是相反的!ADO.NET 版本在那里工作,而 NHibernate 版本不工作(选择 scope_identity() 返回 null)。我多次尝试验证,但无济于事。好吧,实际上这正是我所期望的——@@identity 没问题,而 scope_identity() 失败了。
当然,在 Management Studio 中调用它只会显示来自数据库的结果集,无论 NHibernate 和 ADO.NET 内部发生什么,都是另一个话题。此外,T-SQL SET 定义的几个会话属性在两个场景中是不同的(Management Studio 查询与运行时的应用程序)
这对我来说是一个真正的难题。我会很高兴对此有任何见解。谢谢!