Вопрос

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

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

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

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

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

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

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

Это было полезно?

Решение

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

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.Error, чтобы он проверял каждое имя свойства через IDataErrorInfo[string ColumnName] и объединял возможные сообщения об ошибках.Если он пуст, значит, все в порядке.(не уверен, что Error предназначен для использования таким образом, но я это делаю)

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top