Изменение сущностей в EntityFramework - PullRequest
3 голосов
/ 29 апреля 2009

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

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

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

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

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

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

У кого-нибудь есть хороший учебник или пример?

Ответы [ 3 ]

3 голосов
/ 02 мая 2009

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

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

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

Alex

1 голос
/ 29 апреля 2009

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

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

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

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

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

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

1 голос
/ 29 апреля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...