Ваше обновление ...
var f = db.Foos.First(x => someEqualityTest(foo));
f = foo;
... не будет работать, потому что вы вообще не меняете загруженный и присоединенный объект f
, вы просто перезаписываете переменную f
с помощьюобособленный объект foo
.Прикрепленный объект все еще находится в контексте, но он не был изменен после загрузки, и у вас больше нет переменной, которая указывает на него.SaveChanges
ничего не будет делать в этом случае.
У вас есть "стандартные опции":
var f = db.Foos.First(x => someEqualityTest(foo));
db.Entry(f).State = EntityState.Modified;
или просто
db.Entry(foo).State = EntityState.Modified;
// attaches as Modified, no need to load f
Это помечает ВСЕ свойства какизменен - независимо от того, действительно ли они изменились или нет - и отправит ОБНОВЛЕНИЕ для каждого столбца в базу данных.
Второй параметр, который помечает только действительно измененные свойства как измененные и отправляет только ОБНОВЛЕНИЕ для измененныхколонки:
var f = db.Foos.First(x => someEqualityTest(foo));
db.Entry(f).CurrentValues.SetValues(foo);
Теперь, когда нужно обновить 2 миллиона объектов, у вас нет «стандартной» ситуации, и вполне возможно, что оба варианта - особенно второй, который, вероятно, использует отражение для внутреннего сопоставления имен свойствисходный и целевой объекты - слишком медленные.
Наилучшим вариантом, когда дело доходит до производительности обновлений, являются прокси отслеживания изменений .Это будет означать, что вам нужно пометить КАЖДОЕ свойство в вашем классе сущности как virtual
(не только свойства навигации, но и скалярные свойства) и что вы не отключаете создание прокси отслеживания изменений (оно включено по умолчанию).
Когда вы загружаете ваш объект f
из базы данных, EF создаст динамический прокси-объект (производный от вашей сущности), аналогично прокси-серверам с отложенной загрузкой, в котором код вводится в каждый установщик свойств для поддержкипометка, если свойство было изменено или нет.
Отслеживание изменений, предоставляемое прокси, намного быстрее, чем отслеживание изменений на основе снимка (что происходит в SaveChanges
или DetectChanges
).
Однако я не уверен, что два указанных выше варианта работают быстрее, если вы используете прокси-серверы отслеживания изменений.Вполне возможно, что вам потребуются ручные присвоения свойств для достижения максимальной производительности:
var f = db.Foos.First(x => someEqualityTest(foo));
f.Property1 = foo.Property1;
f.Property2 = foo.Property2;
// ...
f.PropertyN = foo.PropertyN;
По моему опыту в аналогичной ситуации обновления с несколькими тысячами объектов не существует реальной альтернативы прокси отслеживания изменений в отношении производительности.