在 DataAdapter.Update/Refresh 后未设置 DataTable 标识列,使用“而不是”触发器(SqlServer 2005)

Posted

技术标签:

【中文标题】在 DataAdapter.Update/Refresh 后未设置 DataTable 标识列,使用“而不是”触发器(SqlServer 2005)【英文标题】:DataTable identity column not set after DataAdapter.Update/Refresh on table with "instead of"-trigger (SqlServer 2005) 【发布时间】:2010-03-31 08:01:41 【问题描述】:

在我们的单元测试中,我们使用普通的 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 查询与运行时的应用程序)中有所不同

这对我来说是一个真正的难题。我会很高兴对此有任何见解。谢谢!

【问题讨论】:

【参考方案1】:

找到了。标识值实际上已传输到 DataTable 中,只是不在我预期的列中。 ADO.NET 没有使用现有列“id”,而是创建了一个新列“Column1”。

原因是instead-of触发器末尾的这一行:

select @@identity 

不幸的是,NHibernate 似乎需要在而不是触发器的末尾“选择@@identity”(这在 Hibernate 论坛帖子中提到过,我现在再次验证了它 - 这确实是必要的)。但是我可以从这里开始(适应 NHibernate 方言是一种可能性)...

【讨论】:

以上是关于在 DataAdapter.Update/Refresh 后未设置 DataTable 标识列,使用“而不是”触发器(SqlServer 2005)的主要内容,如果未能解决你的问题,请参考以下文章

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据