实体框架无法使用复合键更新数据(Oracle) [英] Entity Framework Can't Update Data In Table With Composite Key (Oracle)

查看:116
本文介绍了实体框架无法使用复合键更新数据(Oracle)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  var connection = new DbContextProvider(()=> new DatabaseConnection()); 
var repo = new Repository(connection);
var deltas = repo.Queryable< Deltas>()。其中​​(d => d.Volume.SubmissionId == 88921).ToList();
var deltaToUpdate = deltas.First();
deltaToUpdate.RecordedVolume = 0;
repo.Flush(); - 背景中的context.SaveChanges()

我们总是收到以下内容:


System.InvalidOperationException:属性COPY_ID是对象的关键信息
的一部分,无法修改。


COPY_ID是密钥的一部分,但是是一个StoredGeneratedPettern = Identity,它在事务中没有更改。



任何帮助赞赏。



这是完整的堆栈:


系统.InvalidOperationException:属性COPY_ID是对象的密钥信息
的一部分,无法修改。
在Data.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata,Int32 ordinal,String memberName)



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



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



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



在系统。System.Data.Objects.Internal.SnapshotChangeTrackingStrategy.SetCurrentValue(String) 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)

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

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)



at System.Data.Mapping.Update.Internal.Upda teTranslator.Update(IEntityStateManager stateManager,IEntityAdapter适配器)



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


$ b $在System.Data.Objects.ObjectContext.SaveChanges(SaveOptions选项)上的b


在System.Data.Entity.Internal.InternalContext.SaveChanges()
在System.Data.Entity.Internal.LazyInternalContext .SaveChanges()
在System.Data.Entity.DbContext.SaveChanges()


更新
我们已经跟踪了数据库的相互作用,并且显示以下SQL在数据库上成功运行,当它返回到EF时抛出错误(并且更改未提交):

  declare 
COPY_IDnumber(10,0);
CODS_IDnumber(10,0);
PERIOD_IDnumber(7,0);

begin
更新SCHEMA。TABLE
setCOLUMN=:p0
其中(((COPY_ID=:p1)
和(CODS_ID=:p2))
和(PERIOD_ID=:p3))
将COPY_ID,CODS_ID,PERIOD_ID返回到COPY_ID,CODS_ID PERIOD_ID;

打开:p4
将COPY_ID选为COPY_ID,CODS_ID作为CODS_ID,PERIOD_ID作为PERIOD_ID
from dual;
结束

{:p0 = [十进制,0,输入] 0,:p1 = [Int32,0,输入] 222222,:p2 = [Int32,0,输入] 22222,:p3 = [Int32 ,0,Input] 222222,:p4 = [Object,0,Output] NULL}


解决方案

请包括:




  • 实体定义

  • 映射类/配置从

  • SQL表定义



BackPropagateServerGen



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



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



所以,我会猜测您的COPY_ID组合键值被定义为服务器生成的标识符,但是其中一个或两个正在进行:




  • 映射到正在干扰实体框架对于香草UPDATE的视图或存储过程

  • 您有一个或多个触发器在表,视图或存储过程中干扰结果。



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



如果您要映射到视图或存储过程,请尽可能直接映射到表。



使用任何概要分析工具必须捕获代码中执行的SQL。



摘要



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


We have an Oracle table that has a composite key of three columns. These columns are correctly mapped via the Entity Framework Data Model into C# objects. When we query a record from the database and then update a non-key column, we always receive an error saying we are trying to update the primary key (excerpt from a test is below):

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

We always receive the following:

System.InvalidOperationException : The property 'COPY_ID' is part of the object's key information and cannot be modified.

COPY_ID is part of the key but is a StoredGeneratedPettern=Identity and it is not changed in the transaction.

Any help appreciated.

Here is the full stack:

System.InvalidOperationException : The property 'COPY_ID' is part of the object's key information and cannot be modified. 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 context, Object value)

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

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

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

at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options) at System.Data.Entity.Internal.InternalContext.SaveChanges() at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() at System.Data.Entity.DbContext.SaveChanges()

UPDATE We have traced the db interactions and it appears the following SQL is being run successfully on the database, when it returns to EF the error is thrown (and the change not committed):

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 }

解决方案

Please include:

  • The entity definition
  • The mapping class / configuration from the context
  • The SQL table definition

BackPropagateServerGen

Looking at the stack trace, the key thing I see is BackPropagateServerGen.

Entity Framework is running your update against the database, but one of your composite key values (presumably COPY_ID) is actually being altered by the UPDATE call. This server-generated value is coming back from the SQL call, and Entity Framework is then complaining that the key value is being changed out from under it.

So, I would guess that your COPY_ID composite key value is defined as a server-generated identifier, but one or both of these is happening:

  • You're mapping to a view or a stored procedure which is interfering with what Entity Framework would expect of a vanilla UPDATE
  • You have one or more triggers on the table, view or stored procedure that is interfering with the result.

If you have any triggers, disable them temporarily to see if the problem then stops.

If you're mapping to a view or a stored procedure, try mapping directly to the table if possible.

Use whatever profiling tools you have to capture what SQL is being executed by the code.

Summary

I think the UPDATE call is actually reaching the database, but the return result is changing the key value(s), causing Entity Framework to fail, and likely rolling back the UPDATE transaction (depending on what version of EF you're using).

这篇关于实体框架无法使用复合键更新数据(Oracle)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆