实体框架无法使用复合键更新表中的数据(Oracle)

时间:2015-08-03 11:24:29

标签: c# oracle entity-framework

我们有一个Oracle表,其复合键为三列。这些列通过实体框架数据模型正确映射到C#对象。当我们从数据库查询记录然后更新非键列时,我们总是会收到一条错误消息,说我们正在尝试更新主键(下面是测试的摘录):

var connection = new DbContextProvider(() => new DatabaseConnection()); 
var repo = new Repository(connection); 
var deltas = repo.Queryable<Deltas>().Where(d =>d.Volume.SubmissionId == 88921).ToList();
var deltaToUpdate = deltas.First(); 
deltaToUpdate.RecordedVolume = 0;
repo.Flush();  -- Does a context.SaveChanges() in background

我们总是收到以下信息:

  

System.InvalidOperationException:属性'COPY_ID'是其中的一部分   对象的关键信息,不能修改。

COPY_ID是密钥的一部分,但是StoredGeneratedPettern = Identity,并且在事务中不会更改。

任何帮助表示感谢。

这是完整的堆栈:

  

System.InvalidOperationException:属性'COPY_ID'是其中的一部分   对象的关键信息,不能修改。   at Data.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata,Int32 ordinal,String memberName)

     

at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName,Object complexObject,String complexObjectMemberName,ref StateManagerTypeMetadata typeMetadata,ref String changingMemberName,ref Object changingObject)

     

at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName,Object complexObject,String complexObjectMemberName)

     

at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)

     

at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)

     

at System.Data.Objects.Internal.SnapshotChangeTrackingStrategy.SetCurrentValue(EntityEntry entry,StateManagerMemberMetadata member,Int32 ordinal,Object target,Object value)

     

at System.Data.Objects.Internal.EntityWrapper`1.SetCurrentValue(EntityEntry entry,StateManagerMemberMetadata member,Int32 ordinal,Object target,Object value)

     

at System.Data.Objects.EntityEntry.SetCurrentEntityValue(StateManagerTypeMetadata metadata,Int32 ordinal,Object userObject,Object newValue)

     

at System.Data.Objects.ObjectStateEntryDbUpdatableDataRecord.SetRecordValue(Int32 ordinal,Object value)

     

at System.Data.Objects.DbUpdatableDataRecord.SetValue(Int32 ordinal,Object value)

     

at System.Data.Mapping.Update.Internal.UpdateTranslator.SetServerGenValue(P   ropagatorResult上下文中,对象的值)

     

at System.Data.Mapping.Update.Internal.UpdateTranslator.BackPropagateServerGen(List`1 generatedValues)

     

在System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager,IEntityAdapter adapter)

     

at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)

     

在System.Data.Objects.ObjectContext.SaveChanges(SaveOptions选项)   在System.Data.Entity.Internal.InternalContext.SaveChanges()   在System.Data.Entity.Internal.LazyInternalContext.SaveChanges()   在System.Data.Entity.DbContext.SaveChanges()

更新 我们已经跟踪了数据库交互,看来下面的SQL正在数据库上成功运行,当它返回EF时抛出错误(并且未提交更改):

declare 
"COPY_ID" number(10,0); 
"CODS_ID" number(10,0); 
"PERIOD_ID" number(7,0); 

begin 
  update "SCHEMA"."TABLE" 
  set "COLUMN" = :p0 
  where ((("COPY_ID" = :p1) 
  and ("CODS_ID" = :p2)) 
  and ("PERIOD_ID" = :p3)) 
  returning "COPY_ID", "CODS_ID", "PERIOD_ID" into "COPY_ID", "CODS_ID",  "PERIOD_ID"; 

  open :p4 
    for select "COPY_ID" as "COPY_ID", "CODS_ID" as "CODS_ID",           "PERIOD_ID" as "PERIOD_ID" 
  from dual; 
end; 

{ :p0=[Decimal,0,Input]0, :p1=[Int32,0,Input]222222, :p2=[Int32,0,Input]22222, :p3=[Int32,0,Input]222222, :p4=[Object,0,Output]NULL }

1 个答案:

答案 0 :(得分:2)

请包括:

  • 实体定义
  • 来自上下文的映射类/配置
  • SQL表定义

BackPropagateServerGen

查看堆栈跟踪,我看到的关键是BackPropagateServerGen

实体框架正在针对数据库运行更新,但是您的一个复合键值(可能是COPY_ID)实际上正被UPDATE调用更改。此服务器生成的值将从SQL调用返回,然后实体框架抱怨键值正在从其下面更改。

所以,我猜你的COPY_ID复合键值被定义为服务器生成的标识符,但其中一个或两个都在发生:

  • 您正在映射到视图或存储过程,这会干扰Entity Framework对vanilla UPDATE的期望
  • 您在表,视图或存储过程中有一个或多个触发器干扰结果。

如果您有任何触发器,请暂时禁用它们以查看问题是否会停止。

如果要映射到视图或存储过程,请尝试直接映射到表。

使用您拥有的任何分析工具来捕获代码正在执行的SQL。

摘要

我认为UPDATE调用实际上是到达数据库,但返回结果是更改键值,导致实体框架失败,并可能回滚UPDATE事务(取决于您的EF版本)使用)。