Entity Framework 5 обновление записи


Я изучал различные методы редактирования / обновления записи в 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 x запросов на базу данных, чтобы загрузить оригинал, а затем обновить его

Метод 2-Загрузите исходную запись, установите измененные значения

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

плюсы

  • передаются только измененные свойства база данных

минусы

  • представления должны содержать все свойства
  • 2 x запросов на базу данных, чтобы загрузить оригинал, а затем обновить его

Метод 3-Прикрепите обновленную запись и установите состояние в EntityState.Изменено

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

плюсы

  • 1 x запрос к базе данных обновление

минусы

  • не могу указать, какие свойства изменяются
  • представления должны содержать все свойства

вопрос

мой вопрос к вам, ребята; есть ли чистый способ, которым я могу достичь этого набора целей?

  • можно указать, какие свойства изменяются
  • представления не должны содержать все свойства (например, пароль!)
  • 1 x запрос на обновление базы данных

Я понимаю, что это довольно незначительная вещь, чтобы указать, но я могу пропустить простое решение этого. Если не метод один будет преобладать ; -)

7 821

7 ответов:

вы ищете:

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();

я добавил дополнительный метод обновления в мой базовый класс репозитория, который похож на метод обновления, созданный с помощью лесов. Вместо того, чтобы установить весь объект в "измененный", он устанавливает набор отдельных свойств. (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, чтобы сэкономить время. В зависимости от процесса я использую оптимистический или пессимистический контроль параллелизма (я всегда использую оптимистично за исключением параллельных сценариев выполнения, где мне нужно заблокировать некоторые записи с помощью простых операторов sql, это редко, хотя). В зависимости от кода и сценария воздействие может быть уменьшено почти до нуля.

для сценарии на стороне клиента, у вас есть несколько вариантов

  1. использовать модели представления. Модели должны иметь состояние обновления имущества(немодифицированные-вставил-обновил-удалил). Это ответственность клиента, чтобы установить правильное значение для этого столбца в зависимости от действий пользователя (вставка, обновление, удаление). Сервер может либо запросить БД для исходных значений, либо клиент должен отправить исходные значения на сервер вместе с измененными строками. Сервер должен присоединить исходные значения и использовать столбец UpdateStatus для каждой строки, чтобы решить, как обрабатывать новые значения. В этом сценарии я всегда использую оптимистический параллелизм. Это будет делать только инструкции insert-update-delete, а не какие-либо выборки, но для этого может потребоваться какой-то умный код для обхода графика и обновления сущностей (зависит от вашего сценария - приложения). Картограф может помочь, но не обрабатывает логику CRUD

  2. используйте библиотеку, как бриз.js, который скрывает большую часть этой сложности (как описано в 1) и пытается подогнать ее к вашему варианту использования.

надеюсь, это поможет