Поскольку вы начинаете с MergeOption.NoTracking
, ваши сущности Detached
.Затем вы модифицируете и прикрепляете их.Вы должны знать, что Attach приводит к неизменным EntityState - то есть он не изменился, так как он был присоединен к контексту,Таким образом, исходные и текущие значения имеют одинаковый набор значений: измененные .Вот почему он не обновляется после вызова метода SaveChanges.
Я думаю, что вы также неправильно поняли цель метода ApplyCurrentValues
:
Он примет значения предоставленного отдельного объекта и использует его EntityKey, чтобы найти тот же объект в контексте.Затем он заменит текущие скалярные значения присоединенной сущности значениями свойства из отсоединенной сущности.
В вашем случае, когда вы уже прикрепили отсоединенную сущность, вам не нужно вызывать ее, вместо этого вам нужно изменить состояние вашей ReviewNote
сущности на Изменено , чтобы EF выполнялсяподходящие методы обновления для вашего хранилища данных:
ctx.Reviews.Attach(review);
foreach (ReviewNote item in review.ReviewNotes) {
if (item.ReviewNoteID == 0) {
ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Added);
}
else {
key = ctx.CreateEntityKey("ReviewNotes", item);
if (ctx.TryGetObjectByKey(key, out original)) {
// ctx.ApplyCurrentValues(key.EntitySetName, item);
ctx.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);
}
}
}
ctx.ObjectStateManager.ChangeObjectState(review, EntityState.Modified);
ctx.SaveChanges();
РЕДАКТИРОВАТЬ: Другой подход заключается в том, чтобы выполнить тот же запрос и получить объекты ReviewNote в память, а затем вызвать ApplyCurrentValues длякаждый из них, так что только те, у кого есть измененное свойство, перейдут в состояние Modified :
// This time you don't need to attach:
//ctx.Reviews.Attach(review);
// Make sure you have them in the memory:
Review review2 = (from r in ctx.Reviews.Include("ReviewNotes")
where r.ReviewID == reviewID
select r).First();
foreach (ReviewNote item in review.ReviewNotes) {
if (item.ReviewNoteID == 0) {
ctx.ReviewNotes.AddObject(item);
}
else {
key = ctx.CreateEntityKey("ReviewNotes", item);
if (ctx.TryGetObjectByKey(key, out original)) {
// Note that the item is a detached object now:
ctx.ApplyCurrentValues(key.EntitySetName, item);
}
}
}
ctx.ObjectStateManager.ChangeObjectState(review, EntityState.Modified);
ctx.SaveChanges();
Также обратите внимание, что ApplyCurrentValues работает только с скалярные свойства для одного объекта и не будут принимать во внимание свойства навигации, в противном случае мы просто вызовем его один раз для объекта Review без необходимости зацикливаться, чтобы применять его ко всем и каждому ReviewNote.