为GUI的EF Model POCO集合添加功能

时间:2014-02-20 15:34:54

标签: c# wpf entity-framework design-patterns mvvm

我遇到了解决设计问题的最佳方法。我希望得到一些想法/建议。这是一个WPF 4.0桌面应用程序。

我正在使用Entity Framework(v6,模型优先),它为我生成了ObservableCollection个POCO类,我正在使用它作为我的模型的基础。我将这些暴露给我的ViewModel,我的目的是将集合的{ReadOnly版本)从这里暴露给我的View,但是我需要在接口运行之前为集合中的每个对象添加一些行为(这是非常“查看”功能 - 记录与集合的每个成员相对应的用户界面状态,而不是应该保留的数据。

在我看来,我有两个选择:

  1. 通过附加的部分类定义向生成的POCO类添加行为。这似乎是错误的,因为POCO类是Model类,我需要的功能不是Model功能。
  2. 创建一个新类(或子类)以在ViewModel集合中使用,并在Model和VM之间同步集合。数据的同步和重复看起来像一个丑陋的kludge,更不用说重要的额外实现工作和运行时处理。 [编辑:有人建议(并非不合理)这可以通过将原始POCO对象包装在添加功能的类中来实现。请参阅下文,了解为什么这比首次出现时更为复杂]
  3. 是否有解决此类问题的标准方法?

    编辑:使问题参数更具体

    我有一个X的集合,每个集合都包含Y的集合(因为数据库中存在一个 - >多个关系)。对于上面的选项2,我需要包装所有X和所有Y。我可以相对轻松地创建WrappedX的集合,但我不能轻易地将每个X的成员集合更改为WrappedY。我必须在X的包装器中克隆Y个集合,并保留所有Y<> WrappedY个集合同步。如果有更好的方法,这就是让我不自觉地实施选项2的开销。

1 个答案:

答案 0 :(得分:0)

我使用通用包装类来完成此操作。我用它来保存像我选择的POCO模型中的IsSelected。注意:我在我的POCO类中实现了INotifyPropertyChanged,以避免必须将所有属性映射到我的DisplayItem,但听起来你不需要它,因为你的只是readonly。

public class DisplayItemBase<T> : ObservableObject 
{
   private T _Item;
   public T Item
   {
      get { return _Item; }
      set
      {
         if (value == _Item)
            return;

         _Item = value;
         RaisePropertyChanged("Item");
      }
   }

   private bool _IsSelected;
   public bool IsSelected
   {
      get { return _Item; }
      set
      {
         if (value == _Item)
            return;

         _Item = value;
         RaisePropertyChanged("Item");
      }
   }

   //More reusable properties/methods/etc
}

然后,如果我有一个特定的POCO实体需要特定的UI相关功能而不属于我的任何其他POCO,我会为那个继承自DisplayItemBase的那个创建一个特定的类。 / p>

public class MyEntityDisplayItem : DisplayItemBase<MyEntity>
{
    private DisplayItemCollectionBase<ChildEntity> _ChildEntities;
    public DisplayItemCollectionBase<ChildEntity> ChildEntities
    {
       get { return _ChildEntities; }
       set
       {
           if (value == _ChildEntities)
              return;

           _ChildEntities = value;
           RaisePropertyChanged("ChildEntities");
       }
    }

    public MyEntityDisplayItem(MyEntity myEntity)
    {
        ChildEntities = new DisplayItemCollectionBase<ChildEntity>(myEntity.ChildEntities);
        Item = myEntity;
    }

    public void AddChildEntity(ChildEntity childEntity)
    {
        ChildEntities.Add(childEntity);
        Item.ChildEntities.Add(childEntity);
    }
}

编辑:回答评论

我还创建了一个DisplayItemCollectionBase,它可以接受我的实体,将其包装起来并将其添加到这样的集合中。

public class DisplayItemCollectionBase<T> : ObservableCollection<DisplayItemBase<T>>
{
   public DisplayItemCollectionBase(IEnumerable<T> items)
   {
       this.AddRange(items)
   }

   public void AddRange(IEnumerable<T> items)
   {
       foreach (var item in items)
          this.Add(item);
   }

   public void Add(T item)
   {
      this.Add(new DisplayItemBase<T>(item));
   }
}

这可能有点不对,因为我会从脑子里走出来,但你应该得到要点。

我在ViewModel中使用它(简化):

public void RefreshFromDatabase()
{
    var repository = new MyEntityRepository();
    IEnumerable<MyEntity> myEntities = repository.GetAll();
    MyEntityCollection = new DisplayItemCollectionBase<MyEntity>(myEntities);
}