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

Chr*_*ris 12 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
Run Code Online (Sandbox Code Playgroud)

我们总是收到以下信息:

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)

在System.Data.Objects.Internal.SnapshotChangeTrackingStrategy.SetCurrentValue(EntityEntry条目,StateManagerMemberMetadata成员,Int32序数,对象目标,对象值)

在System.Data.Objects.Internal.EntityWrapper`1.SetCurrentValue(EntityEntry条目,StateManagerMemberMetadata成员,Int32序数,对象目标,对象值)

在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)

在System.Data.Mapping.Update.Internal.UpdateTranslator.SetServerGenValue(P ropagatorResult context,Object value)

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

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

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

处于System.Data.Entity.InternalContext.SaveChanges()的System.Data.Entity.InternalContext.SaveChanges()处的System.Data.Objects.ObjectContext.SaveChanges(SaveOptions选项)处的System.Data.Entity.LazyInternalContext.SaveChanges()处于System.Data.Entity.DbContext .保存更改()

更新 我们已经跟踪了数据库交互,看来以下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 }
Run Code Online (Sandbox Code Playgroud)

Dav*_*ore 2

请包括:

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

反向传播服务器生成

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

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

因此,我猜测您的 COPY_ID 复合键值被定义为服务器生成的标识符,但其中之一或两者都发生了:

  • 您映射到的视图或存储过程会干扰实体框架对普通更新的期望
  • 表、视图或存储过程上有一个或多个触发器会干扰结果。

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

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

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

概括

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