Изменение сущностей в EntityFramework



У меня есть следующий сценарий:




  1. сущности загружаются из базы данных.

  2. Один из них представляется пользователю в форме (WPF UserControl), где пользователь может редактировать свойства этой сущности.
  3. пользователь может принять решение применить изменения к сущности или отменить редактирование.


Как бы я реализовал нечто подобное с EntityFramework?



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



Я думал о загрузке сущностей с помощью NoTracking и вызове ApplyPropertyChanges после проверки обособленной сущности, но я не совсем уверен в правильном способе сделать это. Документальная часть и EntityFramework на MSDN является очень редкие.



Другой способ, который я мог бы придумать, - это Refresh сущность с StoreWins, но мне не нравится сброс изменений при отмене вместо применения изменений при ОК.



Есть ли у кого-нибудь хороший учебник или образец?

589   3  

3 ответов:

Один из вариантов - это то, что вы сказали сделать запрос без отслеживания.

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First(c => c.ID == 232);
Затем клиент может изменить 'customer', как требуется в памяти, и в действительности ничего не происходит в контексте.

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

// get the value from the database
var original = ctx.Customers.First(c => c.ID == customer.ID);
// copy values from the changed entity onto the original.
ctx.ApplyPropertyChanges(customer); .
ctx.SaveChanges();

Теперь, если вам неудобно с запросом по причинам производительности или параллелизма, вы можете добавить новый метод расширения AttachAsModified(...) в контекст objectcontext.

Это выглядит примерно так это:

public static void AttachAsModified<T>(
    this ObjectContext ctx, 
    string entitySet, 
    T entity)
{
    ctx.AttachTo(entitySet, entity);

    ObjectStateEntry entry = 
            ctx.ObjectStateManager.GetObjectStateEntry(entity);

    // get all the property names
    var propertyNames = 
            from s in entry.CurrentValues.DataRecordInfo.FieldMetadata
            select s.FieldType.Name;

    // mark every property as modified    
    foreach(var propertyName in propertyNames)
    {
        entry.SetModifiedProperty(propertyName);
    }
}

Теперь вы можете написать такой код:

ctx.Customers.MergeOption = MergeOption.NoTracking;
var customer = ctx.Customers.First();
// make changes to the customer in the form
ctx.AttachAsModified("Customers", customer);
ctx.SaveChanges();

И теперь у вас нет параллелизма или внешних запросов.

Единственная проблема сейчас-это работа со свойствами FK. Вы, вероятно, должны посмотреть на мой индекс советов для справки здесь: http://blogs.msdn.com/alexj/archive/2009/03/26/index-of-tips.aspx

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

Алекс

Я также предлагаю IEditableObject и дополнительно IDataErrorInfo.

Способ, которым я это делаю, у меня в основном есть viewmodel для сущности, которая принимает сущность в качестве параметра конструктора (в основном объект-оболочка).

В BeginEdit я копирую свойства сущности в свою viewmodel, поэтому, если я отменяю CancelEdit, данные изменяются только в ViewModel, а исходная сущность не изменилась. В EndEdit я просто применяю свойства ViewModel к сущности снова или, конечно, только если проверка прошла успешно.

Для проверки я использую методы IDataErrorInfo. Я просто реализую IDataErrorInfo.Ошибка, так что он проверяет каждое имя свойства через IDataErrorInfo[string columnName] и объединяет возможные сообщения об ошибках. Если он пуст, то все в порядке. (не уверен, что ошибка должна использоваться таким образом, но я это делаю)

Если к моей исходной сущности присоединены другие сущности, например клиент.Заказы, я создаю их как вложенные модели представлений в исходном объекте. модель представления. Исходная ViewModel вызывает методы Begin-,Cancel-,EndEdit / Error своих подмоделей в собственных реализациях этих методов.

Это немного больше работы,но я думаю, что это стоит того, потому что между BeginEdit и EndEdit, вы можете быть уверены, что ничего не меняется без вашего ведома. И наличие фрагмента кода для свойств INotifyPropertyChanged-enabled тоже очень помогает.

Нормальный способ сделать это-привязка к чему-то, что реализует IEditableObject. Если и как это вписывается в структуру сущностей, я не уверен.

Comments

    Ничего не найдено.