Entity Framework не может обновлять данные в таблице с помощью составного ключа (Oracle)
У нас есть таблица Oracle, которая имеет составной ключ из трех столбцов. Эти столбцы корректно отображаются через модель данных Entity Framework в объекты С#. Когда мы запрашиваем запись из базы данных, а затем обновляем не-ключ, всегда получаем ошибку, говорящую о том, что мы пытаемся обновить первичный ключ (выдержка из теста ниже):
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 является частью информацию о ключе объекта и не может быть изменена. в Data.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata, Int32 ординал, String memberName)
в System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, ref StateManagerTypeMetadata typeMetadata, ref String changeMemberName, ref Object changeObject)
в System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
в System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
в 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, int32 ординал, объект ObjectObject объекта, объект newValue)
в System.Data.Objects.ObjectStateEntryDbUpdatableDataRecord.SetRecordValue(Int32 ординал, значение объекта)
в System.Data.Objects.DbUpdatableDataRecord.SetValue(Int32 ординал, значение объекта)
в System.Data.Mapping.Update.Internal.UpdateTranslator.SetServerGenValue(P ropagatorResult контекст, значение объекта)
в System.Data.Mapping.Update.Internal.UpdateTranslator.BackPropagateServerGen(List`1 generatedValues)
в System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, адаптер IEntityAdapter)
в 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()
UPDATE
Мы проследили взаимодействие db, и кажется, что следующий 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
Пожалуйста, укажите:
- Определение сущности
- Класс отображения/конфигурация из контекста
- Определение таблицы SQL
BackPropagateServerGen
Глядя на трассировку стека, ключевая вещь, которую я вижу, это BackPropagateServerGen
.
Entity Framework запускает ваше обновление по отношению к базе данных, но одно из значений вашего составного ключа (предположительно COPY_ID) фактически изменяется при вызове UPDATE. Это генерируемое сервером значение возвращается из SQL-запроса, и Entity Framework затем жалуется, что значение ключа изменяется из-под него.
Итак, я бы предположил, что ваше составное значение COPY_ID определено как сгенерированный сервером идентификатор, но происходит одно или оба из них:
- Вы сопоставляете представление или хранимую процедуру, которая мешает тому, что Entity Framework ожидает от ванильного UPDATE
- У вас есть один или несколько триггеров в таблице, просмотр или хранимая процедура, которые мешают результату.
Если у вас есть триггеры, временно отключите их, чтобы узнать, останавливается ли проблема.
Если вы привязываетесь к просмотру или хранимой процедуре, попробуйте сопоставить их непосредственно с таблицей, если это возможно.
Используйте все инструменты профилирования, которые вы должны уловить, что SQL выполняет код.
Резюме
Я думаю, что вызов UPDATE фактически доходит до базы данных, но результат возврата изменяет значение (-ы) ключа, заставляя Entity Framework терпеть неудачу и, вероятно, откатывая транзакцию UPDATE (в зависимости от того, какая версия EF вы используя).