#c# #entity-framework #.net-core
Вопрос:
Обновление записей с помощью EF, но оно не обновляется соответствующим образом. Я просто хочу обновить только те поля, которые не являются пустыми и измененными. В предыдущем я делал так:
_context.Attach(exist).CurrentValues.SetValues(t);
который обновит все поля, а я этого не хочу.
Есть ли что-нибудь, что я пропустил в своем коде?
public virtual async Tasklt;Tgt; UpdateAsync(T t, object key) { if (t == null) return null; T exist = await _context.Setlt;Tgt;().FindAsync(key); if (exist != null) { // _context.Attach(exist).CurrentValues.SetValues(t); _context.Attach(exist); var entry = _context.Entry(t); Type type = typeof(T); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo property in properties) { if (property.GetValue(t, null) == null) { entry.Property(property.Name).IsModified = false; } } // _context.Attach(exist).CurrentValues.SetValues(t); await _context.SaveChangesAsync(); } return exist; }
Комментарии:
1. В чем смысл этого кода? Вам ничего из этого не нужно для обновления объекта. Загрузите объекты, измените их свойства, вызовите
SaveChangesAsync
, чтобы сохранить все изменения сразу. DbContext уже является универсальной единицей работы с несколькими объектами. DbSet уже является универсальным репозиторием. Изменения уже отслеживаются. И это.Setlt;Tgt;()
может вызвать проблемы с производительностью в более старых версиях ядра EF —DbContext
будет кэшировать метаданные для всех определенных свойств набора баз данных. Только в EF Core 5 (или 6?)Setlt;Tgt;()
также добавлено кэширование2.
In previous I'm doing like this: _context.Attach(exist).CurrentValues.SetValues(t);
зачем и это делать? Если вы изменяете объект, загруженный самим ядром EF, вам это не нужноAttach
. Объект уже прикреплен и отслежен. Вам нужно использовать толькоAttach
для сохранения отдельного объекта, например, отправленного на сервер с помощью PUT. Если вы хотите изменить только измененные свойства, вам нужно найти, что это такое. Один из способов-использоватьPATCH
вместоPUT
и отправлять измененные свойства только вашему контроллеру. В противном случае вам придется фактически загрузить объект и проверить наличие изменений
Ответ №1:
Я использую что-то вроде этого
public virtual async Tasklt;Tgt; UpdateAsync(T t, object key) { if (t == null) return null; T exist = await _context.Setlt;Tgt;().FindAsync(key); if (exist != null) { _context.Entry(exist).CurrentValues.SetValues(t); var result = await Context.SaveChangesAsync(); if (result == 0) return null } return exist; }