我正在使用实体框架4,在表中使用实体框架插入新记录而不是插入触发器而表有一个标识列时,而不是触发器用于根据插入值修改其中一个插入值对于某些逻辑,实体框架引发异常“存储更新,插入或删除语句影响了意外的行数(0)。实体可能已被修改或删除,因为实体已加载。刷新ObjectStateManager条目”。
任何人都可以帮助解决这个异常吗?
答案 0 :(得分:56)
使用Entity Framework 4.1,Ladislav发布的解决方案在触发器主体的末尾添加了一个Scope_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
编辑以处理计算值(感谢Chris Morgan在评论中):
如果表中有任何其他计算值,则还必须将它们包含在SELECT中。例如,如果您使用CreatedDate
列使用GETDATE()
,则可以选择以下内容:
SELECT [AddressId], [CreatedDate] from [dbo].Addresses where @@ROWCOUNT > 0 and AddressId = scope_identity();
答案 1 :(得分:14)
而不是执行触发器而不是实体框架创建的插入操作。这可能是潜在的问题,因为一旦您使用标识列,每个插入后面都会跟着:
select [Id]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
所以问题是替换插入后该查询会发生什么。如果它被执行并返回null,则得到和异常。您可以在触发器中插入记录后添加它,但如果原始查询也被执行则无效。
您可以将触发器更改为插入和修改数据之前或之后。
答案 2 :(得分:2)
您还需要返回标记为已计算
的所有属性select [Id], [YourComputedColumn]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
答案 3 :(得分:0)
我还发现你需要将StoreGeneratedPattern设置为Identity才能使它在我用作主键但未生成标识值的nvarchar列上工作。这适用于后插入触发器的情况,该触发器计算存储在键列中的唯一值。在其他情况下(添加和更新),可能需要将其设置为Computed。