如果ViewModel直接绑定到实体框架模型的副作用

本文关键字:框架 模型 副作用 实体 ViewModel 绑定 如果 | 更新日期: 2023-09-27 18:01:47

我有以下问题(高水平):我的ViewModel有一些可以由用户编辑的属性(在我的视图中)。大多数属性直接绑定到我的实体框架模型。在很多情况下,这导致的问题,我必须分离我的模型,例如,将其保存到数据库后(如果我不这样做,用户在视图中做一些改变,这些变化是自动反映当下一个SaveChanges()被调用)。不幸的是,分离它会导致所有虚拟属性变为空的问题。所以我必须确保在分离对象之前创建适当的"副本"。这会导致很多副作用。


为了让你更好地理解我的问题,一些代码示例(当然是简化的):

我的模型:

public class Child
{
    public int SomeNumber { get; set; }
    public string SomeText { get; set; }
    public int MotherId { get; set; }
    public virtual Mother Mother { get; set; }
    public virtual ICollection<Sibling> Siblings { get; set; }
}

我的视图模型:

public class ChildViewModel : ViewModel
{
    private IGenericRepository<Child> _repository;
    public string SomeText
    {
        get { return MyModel.SomeText; }
        set
        {
            MyModel.SomeText = value;
            RaisePropertyChanged("SomeText");
        }
    }
    public Mother Mother
    {
        get { return MyModel.Mother; }
        set
        {
            MyModel.Mother = value;
            RaisePropertyChanged("Mother");
        }
    }
    public void Save()
    {
        if (MyModel.Id == 0)
        {
            Insert();
        }
        else
        {                
            Update();
        }            
        UnitOfWork.Save();
        _repository.Detach(PrimaryModel);
    }
}

你可以看到ViewModel的属性直接绑定到我的EF模型。在保存中,我必须在保存后分离。如果我不这样做,这将导致以下问题:用户在视图中更改SomeText,但不保存。现在叫UnitOfWork.Save()。修改后的SomeText值被意外保存。这样做的副作用是,母亲属性现在将为空。

为了避免这种情况,我尝试创建对象的"真实"副本。因此,每个模型都必须实现一个方法来复制它的值。在讨论复杂对象时,这变得困难且容易出错。当试图保存"复制"对象时,我有更多的副作用,如错误Attaching an entity of type ... failed because another entity of the same type already has the same primary key value.(特别是"复制"1:many和many:many对象)。


概要:

    通过ViewModel直接绑定Model到View…
  • …如果不拆开,会导致一些副作用。
  • 卸载模型会导致虚拟属性变为null。
  • 为了避免这种情况,可以在分离之前创建对象的副本。
  • 当复制对象非常复杂(多个1:many和many:many关系)时,很难保存复制对象。

这就导致了一个问题:简单的用例(比如"Save data set xyz")——至少在我看来应该是简单的——花费了大量的时间,代码变得越来越复杂。

我怎样才能避免这些陷阱?

如果ViewModel直接绑定到实体框架模型的副作用

解决方案很简单,不要在视图模型中创建引用模型的额外属性。相反,直接绑定到模型

下面是一个例子:

public string SomeText
{
    get { return MyModel.SomeText; }
    set
    {
        MyModel.SomeText = value;
        RaisePropertyChanged("SomeText");
    }
}
在上面的代码中,您在视图模型中创建了一个额外的属性,您不需要这样做。我猜你是这样绑定它的:
<TextBox Text="{Binding SomeText}" ... />
比起创建这个额外的属性,您应该绑定到模型。像这样:
<TextBox Text="{Binding MyModel.SomeText}" ... />

现在,您再也不用担心分离模型了。