插入表而不是来自实体数据框架的触发器时出错

SKu*_*mar 27 sql-server triggers sql-server-2008 entity-framework-4

我正在使用实体框架4,在表中使用实体框架插入新记录而不是插入触发器而表有一个标识列时,而不是触发器用于根据某些逻辑修改插入值之一,实体框架引发异常"存储更新,插入或删除语句影响了意外的行数(0).实体可能已被修改或删除,因为实体已加载.刷新ObjectStateManager条目".

任何人都可以帮助解决这个异常吗?

Rya*_*oss 56

使用Entity Framework 4.1,Ladislav发布的解决方案在触发器主体的末尾添加了一个Range_Identity(),解决了我的问题.为了完整起见,我在这里复制了整个触发器创建.通过此触发器防御,我可以使用context.SaveChanges()向表中添加行.

ALTER TRIGGER [dbo].[CalcGeoLoc]
   ON  [dbo].[Address]
   INSTEAD OF INSERT
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT OFF;

-- Insert statements for trigger here
INSERT INTO Address (Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, GeoLoc, Name)
SELECT Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, geography::Point(Latitude, Longitude, 4326), Name 
FROM Inserted;

select AddressId from [dbo].Address where @@ROWCOUNT > 0 and AddressId = scope_identity();
END
Run Code Online (Sandbox Code Playgroud)

编辑处理计算值(感谢Chris Morgan在评论中):

如果表中有任何其他计算值,则还必须将它们包含在SELECT中.例如,如果您有一个CreatedDate使用的列,GETDATE()您可以像这样选择:

SELECT [AddressId], [CreatedDate] from [dbo].Addresses where @@ROWCOUNT > 0 and AddressId = scope_identity();
Run Code Online (Sandbox Code Playgroud)

  • 你很棒 如果可以的话,我会投票150,000次. (7认同)
  • 如果表中有任何其他计算值,则还必须将它们包含在SELECT中.例如,如果你有使用GETDATE()你会作出选择这样的CreatedDate柱:`SELECT [AddressId] [CreatedDate],从[DBO] .Addresses其中@@ ROWCOUNT> 0且AddressId = SCOPE_IDENTITY();` (4认同)
  • 我添加了"SELECT <columnName> FROM INSERTED;" 到了触发器体的末端,它就成功了. (3认同)
  • 非常有用,但需要注意的是,该解决方案可能无法在 SQL Server 的未来版本中运行。来自 [CREATE TRIGGER 文档](https://msdn.microsoft.com/en-us/library/ms189799.aspx): *从触发器返回结果的功能__将在 SQL Server 的未来版本中删除__。返回结果集的触发器可能会在并非设计用于使用它们的应用程序中导致意外行为。避免在新的开发工作中从触发器返回结果集,并计划修改当前执行此操作的应用程序。* (2认同)

Lad*_*nka 14

而不是执行触发器而不是实体框架创建的插入操作.这可能是潜在的问题,因为一旦您使用标识列,每个插入后面跟着:

select [Id]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
Run Code Online (Sandbox Code Playgroud)

所以问题是替换插入后该查询会发生什么.如果它被执行并返回null,则得到和异常.您可以在触发器中插入记录后添加它,但如果执行原始查询也无济于事.

您可以将触发器更改为插入和修改数据之前或之后.