1

在带有 ADO.NET Entity Framework 4 的 SQL Server 中使用“Instead of”触发器的视图中插入记录时,我得到一个无效操作异常。错误消息显示:

{“对数据库的更改已成功提交,但在更新对象上下文时出错。ObjectContext可能处于不一致状态。内部异常消息:定义EntityKey的键值对不能为null或为空。参数名称:记录"}

@ at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
  at System.Data.Objects.ObjectContext.SaveChanges()

在这个简化的示例中,我创建了两个表,Contacts 和 Employers,以及一个视图 Contacts_x_Employers,它允许我一次在这两个表中插入或检索行。表只有一个名称和一个 ID 属性,视图基于两者的连接:

CREATE VIEW [dbo].[Contacts_x_Employers]
AS
SELECT dbo.Contacts.ContactName, dbo.Employers.EmployerName
FROM dbo.Contacts INNER JOIN dbo.Employers 
ON dbo.Contacts.EmployerID = dbo.Employers.EmployerID

并且有这个触发器:

Create TRIGGER C_x_E_Inserts
   ON  Contacts_x_Employers
   INSTEAD of INSERT
AS 
BEGIN
    SET NOCOUNT ON;

    insert into Employers (EmployerName)
    select i.EmployerName 
        from inserted i
    where  not i.EmployerName in 
    (select EmployerName from Employers)

    insert into Contacts (ContactName, EmployerID)
    select i.ContactName, e.EmployerID 
    from inserted i inner join employers e
    on i.EmployerName = e.EmployerName;

END
GO

.NET 代码如下:

使用 (var Context = new TriggersTestEntities()) { Contacts_x_Employers CE1 = new Contacts_x_Employers(); CE1.ContactName = "J"; CE1.EmployerName = "T"; Contacts_x_Employers CE2 = 新的 Contacts_x_Employers(); CE1.ContactName = "W"; CE1.EmployerName = "C"; Context.Contacts_x_Employers.AddObject(CE1); Context.Contacts_x_Employers.AddObject(CE2); Context.SaveChanges(); // 有错误的行 }

 </p>

SSDL 和 CSDL(视图节点):

<EntityType Name="Contacts_x_Employers">
   <Key>
    <PropertyRef Name="ContactName" />
<PropertyRef Name="EmployerName" />
   </Key>
<Property Name="ContactName" Type="varchar" Nullable="false" MaxLength="50" />
<Property Name="EmployerName" Type="varchar" Nullable="false" MaxLength="50" />
 </EntityType>

<EntityType Name="Contacts_x_Employers">
  <Key>
     <PropertyRef Name="ContactName" />
     <PropertyRef Name="EmployerName" />
   </Key>
   <Property Name="ContactName" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
   <Property Name="EmployerName" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
</EntityType>

可以在ftp://JulioSantos.com/files/TriggerBug/的 TestViewTrggers.zip 中找到 Visual Studio 解决方案和重新创建整个应用程序的 SQL 脚本。我感谢可以提供的任何帮助。我已经花了几天的时间来解决这个问题。

4

1 回答 1

1

当我尝试使用“代替插入”和“代替更新”触发器在视图中插入一行时,我偶然发现了同样的问题。

我想我找到了一个解决方案:当 Visual Studio 的向导将您的视图放到您的模型中时,它会在某些属性(可能是您的实体的键)上添加一个 StoreGeneratedPattern="Identity"。

在常规表上生成请求时,此属性告诉实体框架期望返回一个 ID,因此它在插入末尾附加一个 select scope_identity()。

现在使用可更新视图,scope_identity 被搞砸了,因为插入发生在另一个范围内并且它返回 null,因此插入失败。

如果您从模型中删除此 StoreGeneratedPattern="Identity",实体框架不会附加 select scope_identity() 并且插入工作正常。

我希望这可以解决您的问题,并且不会为时已晚。

干杯

更多细节在这里:http ://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/9fe80b08-0b67-4163-9cb0-41dee5115148/

于 2011-03-08T15:23:04.170 回答