在我们的单元测试中,我们使用普通的ADO.NET (DataTable,DataAdapter)来准备数据库。检查结果,而测试的组件本身在NHibernate 2.1下运行。.NET版本为3.5,SqlServer版本为2005。
数据库表具有作为主键的标识列。有些表应用insert-of-insert/update触发器(这是因为向后兼容,我不能更改)。触发器通常是这样工作的:
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发出的insert语句(由瘦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使用这种insert语句:
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版本不能(select scope_identity()返回null)。我试着验证了几次,但都没有结果。实际上,这正是我所期望的-- @@identity可以接受,而scope_identity()会失败。
当然,在Management Studio中调用它只会显示来自数据库的结果集,无论NHibernate和ADO.NET中发生了什么,都是另一个主题。此外,由T-SQL集定义的几个会话属性在这两个场景中是不同的(Management Studio查询与运行时的应用程序)
这对我来说是一个真正的难题。我很高兴有任何关于这方面的见解。谢谢!
发布于 2010-03-31 22:06:53
找到了。identity值实际上传输到了DataTable中,只是不在我期望的列中。ADO.NET没有使用现有的列"id",而是创建了一个新的列"Column1“。
原因是instead-of触发器末尾的这一行:
select @@identity 不幸的是,NHibernate似乎需要在instead-of触发器的末尾加上"select @@identity“(这是在Hibernate论坛的帖子中提到的,我现在再次验证了这一点--这确实是必要的)。但我可以从这里开始(适应NHibernate方言是一种可能)……
https://stackoverflow.com/questions/2551298
复制相似问题