Отслеживание изменений и параллелизм - может ли это потерпеть неудачу? - PullRequest
1 голос
/ 08 сентября 2010

Я возился с выражениями - и, возможно, я вышел за пределы своих возможностей - но здесь все идет ... Я реализовал «безопасную от типов» реализацию INotifyPropertyChanged (пример: здесь ), но пошли немного дальше и включили отслеживание изменений:

public abstract BaseViewModel<TEntity>:INotifyPropertyChanged
{
    private readonly IBaseChangeTracker<TEntity> _changeTracker;
    protected void OnPropertyChanged<T>(Expression<Func<T>> property, T value)
    {
        _changeTracker.AddChange(property, value);
        OnPropertyChanged(property);
    }
    protected virtual void OnPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
    {
        if (PropertyChanged == null) return;
        PropertyChanged(this, new PropertyChangedEventArgs(property.GetMemberInfo().Name));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

public abstract class BaseChangeTracker<TEntity>:IBaseChangeTracker<TEntity>
{
    private readonly IDictionary<Expression, object> _changes = new Dictionary<Expression, object>();
    public void AddChange<T>(Expression<Func<T>> expression, T newValue)
    {
        _changes.Add(expression, newValue);
    }

    public void ApplyChanges(TEntity entity)
    {
        foreach (var change in _changes)
        {
            var property = typeof(TEntity).GetProperty(change.Key.GetMemberInfo().Name);
            property.SetValue(entity, change.Value, null);
        }
    }

    public virtual void CopyCurrentState(TEntity entity)
    {
        _changes.Clear();

    }
    public virtual void ResetEntity(TEntity entity)
    {
        _changes.Clear();
    }

    public bool HasUnsavedChanges
    {
        get { return _changes.Any(); }
    }
}

Это может показаться немного чрезмерным - у каждого объекта будет свой собственный ChangeTracker, сохраняющий исходное состояние объекта при загрузке, и он может сбросить его обратно на эти, но идея заключается в том, что если при попытке сохранить обновленную сущность возникает конфликт параллелизма, я перезагружаю сущность из базы данных и запускаю ее через .ApplyChanges и пытаюсь сохранить ее снова.Это удалит около 95% моих проблем с параллелизмом ... если это сработает.Мои тесты показывают, что для ограниченных объектов это работает, но это с простыми изменениями свойств.

Известная проблема:

  1. Мне еще предстоит найти элегантный способ обработки коллекций.

Что еще мне не хватает - или есть явные недостаткив моем дизайне?

1 Ответ

1 голос
/ 08 сентября 2010

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

Инкапсуляция изменений в командах - это очень аккуратный способ циклического / повторного цикла изменений, с дополнительными преимуществами (1) приятной функции, которая добавляет ценность приложению, (2) вы можете обернуть множество действий в любой заданный команда, например, получение уведомлений об изменении события для поддержки привязки данных в направлениях do и undo.

Кроме того, управление изменениями коллекции не более или менее сложно, чем простые обновления свойств.

Специфично для размещенного вами кода, реализация OnPropertyChanged никогда не вызовет событие PropertyChanged, потому что вы вызываете return после оператора if(), а затем снова в пустых скобках (они не соответствуют if состояние).

  if (PropertyChanged == null) return; // this returns based on if
    {
        return; // this returns no matter what
    }

Кроме того, кажется, что пользователь никогда не увидит никаких изменений в пользовательском интерфейсе. Значения не обновляются до тех пор, пока не будет вызван ApplyChanges, а когда это произойдет, события PropertyChanged не будет. (Возможно, я не правильно следую вашему коду, но просто просматривая его, похоже, это так).

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