【问题标题】:error when inserting into table having instead of trigger from entity data framework插入表时出现错误,而不是从实体数据框架触发
【发布时间】:2011-08-14 19:51:07
【问题描述】:

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

谁能帮助解决这个异常?

【问题讨论】:

  • 您没有将答案标记为正确的原因是什么?下面瑞安格罗斯的回答为我解决了这个完全相同的问题。

标签: sql-server sql-server-2008 entity-framework-4 triggers


【解决方案1】:

使用 Entity Framework 4.1,Ladislav 发布的将 Scope_Identity() 的 Select 添加到触发器主体末尾的解决方案为我解决了这个问题。为了完整起见,我在这里复制了整个触发器的创建。通过这个触发器定义,我可以使用 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

编辑处理计算值(感谢 cmets 中的 Chris Morgan):

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

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

【讨论】:

  • 我添加了“SELECT FROM INSERTED;”到触发器主体的末尾,它成功了。
  • 你太棒了。如果可以的话,我会投票赞成 150,000 次。
  • 如果表中有任何其他计算值,您也必须将它们包含在 SELECT 中。例如,如果您有一个使用 GETDATE() 的 CreatedDate 列,您可以像这样进行选择:SELECT [AddressId], [CreatedDate] from [dbo].Addresses where @@ROWCOUNT > 0 and AddressId = scope_identity();
  • 这个答案解决了我的问题,应该标记为正确。
  • 非常有用,但需要注意的是,此解决方案可能不适用于 SQL Server 的未来版本。来自CREATE TRIGGER documentation从触发器返回结果的功能将在 SQL Server 的未来版本中删除。返回结果集的触发器可能会在不是为使用它们而设计的应用程序中导致意外行为。避免在新开发工作中从触发器返回结果集,并计划修改当前执行此操作的应用程序。
【解决方案2】:

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

select [Id]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()

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

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

【讨论】:

  • 您能否详细说明“但如果同时执行原始查询也无济于事。”
  • 在这个答案中添加信息,在sql server中不存在insert之前,insert之后比insert慢得多。
【解决方案3】:

您还需要返回标记为 Computed

的所有属性
select [Id], [YourComputedColumn]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()

【讨论】:

    【解决方案4】:

    我还发现您需要将 StoreGeneratedPattern 设置为 Identity 才能使其在我用作主键但未生成标识值的 nvarchar 列上工作。这是针对后插入触发器的情况,该触发器计算了一个唯一值以存储在键列中。在其他情况下(添加和更新),可能需要将其设置为 Computed。

    【讨论】:

      猜你喜欢
      • 2014-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-30
      相关资源
      最近更新 更多