c# - поиск - savechanges entity framework не работает




Entity Framework 5 Обновление записи (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();
}    

Pros

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

Cons

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

Способ 2 - Загрузка оригинальной записи, установка измененных значений

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

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

Pros

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

Cons

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

Способ 3 - Прикрепите обновленную запись и установите состояние EntityState.Modified

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

Pros

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

Cons

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

Вопрос

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

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

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


В зависимости от вашего варианта использования применяются все вышеперечисленные решения. Вот как я обычно это делаю:

Для кода на стороне сервера (например, пакетный процесс) я обычно загружаю сущности и работаю с динамическими прокси. Обычно в пакетных процессах необходимо загружать данные в любое время в момент запуска службы. Я пытаюсь загрузить пакет данных вместо использования метода find, чтобы сэкономить некоторое время. В зависимости от процесса я использую оптимистический или пессимистический контроль параллелизма (я всегда пользуюсь оптимизмом, за исключением сценариев параллельного выполнения, когда мне нужно блокировать некоторые записи с помощью простых операторов sql, это редко бывает). В зависимости от кода и сценария воздействие может быть уменьшено почти до нуля.

Для сценариев клиентской стороны у вас есть несколько вариантов

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

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

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


Мне очень нравится принятый ответ. Я считаю, что есть еще один способ приблизиться к этому. Допустим, у вас есть очень короткий список свойств, которые вы бы никогда не хотели включать в представление, поэтому при обновлении объекта они будут опущены. Предположим, что эти два поля: Пароль и 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();   

Этот пример позволяет существенно оставить свою бизнес-логику после добавления нового поля в таблицу «Ваши пользователи» и в «Вид».


Ты ищешь:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
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();
    }
}




entity-framework-5