Ответ 1
Вы ищете:
db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();
Я изучал различные методы редактирования/обновления записи в Entity Framework 5 в среде ASP.NET MVC3, но пока ни один из них не отметит все необходимые мне окна. Я объясню, почему.
Я нашел три метода, о которых я упомянул плюсы и минусы:
Метод 1 - Загрузка исходной записи, обновление каждого свойства
var original = db.Users.Find(updatedUser.UserId);
if (original != null)
{
original.BusinessEntityId = updatedUser.BusinessEntityId;
original.Email = updatedUser.Email;
original.EmployeeId = updatedUser.EmployeeId;
original.Forename = updatedUser.Forename;
original.Surname = updatedUser.Surname;
original.Telephone = updatedUser.Telephone;
original.Title = updatedUser.Title;
original.Fax = updatedUser.Fax;
original.ASPNetUserId = updatedUser.ASPNetUserId;
db.SaveChanges();
}
Доводы
против
Метод 2 - Загрузка исходной записи, установка измененных значений
var original = db.Users.Find(updatedUser.UserId);
if (original != null)
{
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();
}
Доводы
против
Метод 3 - Прикрепите обновленную запись и установите состояние в EntityState.Modified
db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();
Доводы
против
Вопрос
Мой вопрос вам, ребята; есть ли чистый способ, которым я могу достичь этого набора целей?
Я понимаю, что это довольно незначительная вещь, но я могу пропустить это простое решение. Если ни один из методов не будет преобладать, -)
Вы ищете:
db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();
Мне очень нравится принятый ответ. Я считаю, что есть еще один способ приблизиться к этому. Скажем, у вас есть очень короткий список свойств, которые вы бы никогда не хотели включать в представление, поэтому при обновлении объекта они будут опущены. Скажем, что эти два поля - Пароль и SSN.
db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;
entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;
db.SaveChanges();
Этот пример позволяет существенно оставить свою бизнес-логику после добавления нового поля в таблицу "Ваши пользователи" и в "Вид".
foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
if (propertyInfo.GetValue(updatedUser, null) == null)
propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();
Я добавил дополнительный метод обновления в базовый класс моего репозитория, который похож на метод обновления, созданный Scaffolding. Вместо того, чтобы установить весь объект на "измененный", он устанавливает набор индивидуальных свойств. (T является общим параметром класса.)
public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
Context.Set<T>().Attach(obj);
foreach (var p in propertiesToUpdate)
{
Context.Entry(obj).Property(p).IsModified = true;
}
}
А затем вызвать, например:
public void UpdatePasswordAndEmail(long userId, string password, string email)
{
var user = new User {UserId = userId, Password = password, Email = email};
Update(user, u => u.Password, u => u.Email);
Save();
}
Мне нравится одна поездка в базу данных. Вероятно, лучше сделать это с помощью моделей взглядов, чтобы избежать повторения наборов свойств. Я еще не сделал этого, потому что я не знаю, как не доводить сообщения проверки на моделях проверки модели просмотра в моем проекте домена.
public interface IRepository
{
void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}
public class Repository : DbContext, IRepository
{
public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
{
Set<T>().Attach(obj);
propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
SaveChanges();
}
}
Просто добавьте список опций. Вы также можете захватить объект из базы данных и использовать инструмент автоматического сопоставления, например Auto Mapper, чтобы обновить части записи, которую вы хотите изменить..
В зависимости от вашего варианта использования применяются все вышеперечисленные решения. Вот как я обычно это делаю:
Для кода на стороне сервера (например, пакетный процесс) я обычно загружаю объекты и работаю с динамическими прокси. Обычно в пакетных процессах необходимо загружать данные в любое время в момент запуска службы. Я пытаюсь загрузить пакет данных вместо использования метода find, чтобы сэкономить некоторое время. В зависимости от процесса я использую оптимистичный или пессимистический элемент управления concurrency (я всегда пользуюсь оптимизмом, за исключением сценариев параллельного выполнения, где мне нужно блокировать некоторые записи с помощью простых sql-операторов, это редко бывает). В зависимости от кода и сценария воздействие может быть уменьшено до нуля.
Для сценариев клиентской стороны у вас есть несколько опций
Используйте модели просмотра. Модели должны иметь свойство UpdateStatus (немодифицированный-вставленный-обновленный-удаленный). Клиент обязан установить правильное значение этого столбца в зависимости от действий пользователя (insert-update-delete). Сервер может либо запросить db для исходных значений, либо клиент должен отправить исходные значения на сервер вместе с измененными строками. Сервер должен прикрепить исходные значения и использовать столбец UpdateStatus для каждой строки, чтобы решить, как обрабатывать новые значения. В этом сценарии я всегда использую оптимистичный concurrency. Это будет делать только инструкции insert-update-delete, а не какие-либо выборки, но может понадобиться какой-нибудь умный код для просмотра графика и обновления сущностей (зависит от вашего сценария-приложения). Mapper может помочь, но не обрабатывает логику CRUD
Используйте библиотеку, такую как breeze.js, которая скрывает большую часть этой сложности (как описано в 1) и попытайтесь поместить ее в свой прецедент.
Надеюсь, что это поможет