Обновляйте только некоторые свойства объекта EF, для которых не установлено значение NULL - PullRequest
3 голосов
/ 25 января 2012

У меня есть браузер, отправляющий JSON, но он содержит только свойства данной модели, которые были изменены.Поэтому, как только WCF DataContractJsonSerializer выполнит свою работу, у меня есть объект, который, возможно, будет заполнен только полями ID и Description.

Присоединение этого к DbContext как есть, приведет к обновлению поля описания, но всех других полейбыть установленным по умолчанию для их типов в базе данных.Это связано с тем, что если WCF не видит свойство, указанное в JSON, оно пропускает его, а это означает, что свойство в экземпляре будет просто использовать значение по умолчанию для типов в соответствии с автоматически внедряемым свойством.

Так что это означает, что мне нужно решить, какие поля были переданы, не имея доступа к самому JSON.Фактически это может быть XML на проводе, поэтому все, с чем я могу работать, это частично сериализованный объект.

Что кажется наиболее логичным, так это использовать null в качестве специального значения, означающего, что это свойство не имеетСериализирован.Итак, в конструкторе модели POCO я установил все свойства на null .

В методе Update я затем использую этот сериализованный объект в качестве заглушки.Мне нужно пройтись по каждому свойству, и если значение не установлено на null , тогда я устанавливаю его состояние как измененное.Насколько я могу судить, это работает без каких-либо побочных эффектов, но я просто не уверен, что это способ сделать что-то подобное.

Одно ограничение, которое он добавляет, заключается в том, что клиент больше не может преднамеренно устанавливать для свойства значение null, поскольку это обновление будет потеряно.Одним из способов решения этой проблемы является специальное значение типа int, которое можно установить для представления значения null в базе данных, и, возможно, пустая строка для представления значения null в базе данных и наличие кода в обновлении для поиска этих специальных значений, а затем установите свойство entityк нулю.Далеко от идеала и может быть подвержен ошибкам.

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

Саммерсу: Как я могу определить, какие свойства наэкземпляр модели был установлен DataContractSerializer / DataContractJsonSerializer и использует значения по умолчанию из своего конструктора.Использование специальных значений проблематично, так как клиент может захотеть установить что-то в пустую строку, или в 0, или в -1, или даже в нулевое значение.

public T Update(T obj)
{
    var entity = ds.Attach(obj);

    // For each property in the model
    foreach (var p in typeof(T).GetProperties())
    {
        // Get the value of the property
        var v = p.GetValue(obj, null);

        // Assume null means that the property wasn't passed from the client
        if (v == null)
            continue;

        // Set this property on the entity to modified unless it's ID which won't change
        if (p.Name != "ID")
            dc.Entry(entity).Property(p.Name).IsModified = true;
    }

    dc.SaveChanges();
    return entity;
}

ОБНОВЛЕНИЕ: Используя ответ Хаммерштейна нижедля самостоятельного отслеживания моделей я обновил функцию обновления, как показано ниже.К сожалению, из-за моего использования атрибута Required в моделях для проверки перед сохранением EF генерирует колебание при использовании экземпляра заглушки, который содержит нули для неизмененных значений.Можно подумать, что EF осознает, что в рамках своей проверки некоторые поля установлены как неизмененные, но, увы, нет, поэтому я вынужден выполнить чтение, а затем обновить его.На самом деле это может быть хорошим кандидатом на отдельный вопрос, чтобы опубликовать, чтобы попытаться избежать чтения.

public virtual T Update(T obj)
{
    var entity = ds.Find(obj.ID);

    ((TrackedModel)obj).Modified.ForEach(p => { 
        var prop = dc.Entry(entity).Property(p.PropertyName);
        prop.CurrentValue = p.NewValue;
        prop.IsModified = true;
    });

    dc.SaveChanges();
    return entity;
}

1 Ответ

2 голосов
/ 25 января 2012

Моим решением этой проблемы была модель отслеживаемых изменений, я создал абстрактный базовый класс, который имел список строк, затем для каждого свойства в моей модели я вызвал метод NotifyChanged ("MyProperty"), который добавил свойствосписок.

Поскольку привязка модели будет устанавливать только те поля, которые были отправлены обратно, вы должны получить точный список полей, которые были изменены.

Затем я перебираю список и устанавливаю значения для моей сущности.

Не чисто, но для моей цели это сработало.

Обновление : мое решение требовало от меня ухода от авто-свойств и написания их от руки.В установщике после установки значения я вызываю NotifyChanged.Я использую это с регулярной привязкой модели MVC, я не думаю, что у меня есть рабочий пример передачи объекта в виде JSON и десериализации.Вы можете посмотреть на JSON.NET, контролируя сериализацию / десериализацию. Я полагаю, вы можете сказать ей игнорировать значения свойств по умолчанию и т. Д.

...