代码之家  ›  专栏  ›  技术社区  ›  Goblin

变更跟踪和并发性-这会失败吗?

  •  1
  • Goblin  · 技术社区  · 14 年前

    我一直在玩弄表达式-我可能已经超越了我的能力-但这里…我已经实现了“类型安全”的inotifyPropertyChanged实现(例如 here ,但更进一步,包括变更跟踪:

    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 回复  |  直到 14 年前
        1
  •  1
  •   Jay    14 年前

    我认识到这不是您问题的直接答案,但是您可以考虑使用命令模式来实现撤消/重做堆栈。

    在命令中封装更改是一种非常整洁的循环/重新循环更改的方法,其附加的好处是:(1)为应用程序增加值的一个很好的功能;(2)您可以在任何给定的命令中包装许多操作,例如在do和undo方向上为数据绑定支持引发事件更改通知。

    此外,与简单的属性更新相比,管理集合更改的挑战不多也不少。

    特定于您发布的代码, OnPropertyChanged 实施永远不会提高 PropertyChanged 因为你打电话 return if() 语句,然后在裸括号中再次(这些语句与 if 条件)

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

    此外,用户似乎从未在UI中看到任何更改。值在之前不会更新 ApplyChanges 被调用,当它被调用时 属性更改 事件。(我可能没有正确地遵循您的代码,但只是仔细检查一下,情况似乎是这样的)。