如果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")——至少在我看来应该是简单的——花费了大量的时间,代码变得越来越复杂。
我怎样才能避免这些陷阱?
解决方案很简单,不要在视图模型中创建引用模型的额外属性。相反,直接绑定到模型。
下面是一个例子:
public string SomeText
{
get { return MyModel.SomeText; }
set
{
MyModel.SomeText = value;
RaisePropertyChanged("SomeText");
}
}
在上面的代码中,您在视图模型中创建了一个额外的属性,您不需要这样做。我猜你是这样绑定它的:
<TextBox Text="{Binding SomeText}" ... />
比起创建这个额外的属性,您应该绑定到模型。像这样:<TextBox Text="{Binding MyModel.SomeText}" ... />
现在,您再也不用担心分离模型了。