EF4:ObjectContext在插入带触发器的视图时不一致

时间:2011-02-11 21:02:57

标签: exception entity-framework-4 view triggers objectcontext

在使用ADO.NET Entity Framework 4的SQL Server中使用“而不是”触发器的视图中插入记录时,我收到无效操作异常。 错误消息显示:

  

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

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

在这个简化的例子中,我创建了两个表,Contacts和Employers,以及一个Contacts_x_Employers视图,它允许我一次在这两个表中插入或检索行。表只有Name和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 = new Contacts_x_Employers();             CE1.ContactName =“W”;             CE1.EmployerName =“C”;             Context.Contacts_x_Employers.AddObject(CE1);             Context.Contacts_x_Employers.AddObject(CE2);             Context.SaveChanges(); //行有错误         }

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脚本。 我感谢您提供的任何帮助。我已经花了几天时间研究这个问题。

1 个答案:

答案 0 :(得分: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/