将EF4与Caliburn.Micro绑定:我应该将实体公开为ViewModel的属性吗?

5
使用Caliburn.Micro,我想了解将EF4实体公开为ViewModel属性的优缺点(这是在这里这里讨论的一种技术)。这样可以避免为每个字段编写getter和setter(请参见下面的OneCustomer)。缺点是我需要在XAML中编写所有绑定语句(下面的LastName不在ViewModel中,但确实需要XAML绑定)。如果我坚持使用为每个字段填充ViewModel属性的预定技术(如下面的FirstName),最终我将不得不编写大量额外的代码,以便调用NotifyOfProperyChange。该应用程序将非常庞大。我应该将每个实体公开为ViewModel属性吗?

在我的ViewModel中:

private MyEntities _context = new MyEntities();
private BindableCollection<Customer> _custBindableCollection; 
private Customer _oneCustomer;
private string _firstName;

public void Load() 
{
    _custBindableCollection = new BindableCollection<Customer>(_context.Customers.Where(row => row.CustomerType == "FOO"));
    AllCustomers = _custBindableCollection;
    _oneCustomer = _custBindableCollection.FirstOrDefault();
    FirstName = _oneCustomer.FirstName;
    OneCustomer = _oneCustomer;
}

public BindableCollection<Customer> AllCustomers
{ 
get { return _custBindableCollection;}
set {_custBindableCollection = value;
      NotifyOfPropertyChange(() => AllCustomers);}
}

public Customer OneCustomer
{
 get { return _oneCustomer;}
 set { _oneCustomer = value;
        NotifyOfPropertyChange(() => OneCustomer);}
} 

public string FirstName
{
    get { return _firstName; }
    set {
        _firstName = value;
        _oneCustomer.FirstName = value;
        NotifyOfPropertyChange(() => FirstName);
        NotifyOfPropertyChange(() => CanSaveChanges);
    }
}

public void SaveChanges()
{ _context.SaveChanges(); }

public bool CanSaveChanges { get { return IsValid; } }

我的观点:

<StackPanel>
<StackPanel Orientation="Horizontal">
    <Label Content="First Name:" />
    <TextBox x:Name="FirstName" />
</StackPanel>
<StackPanel Orientation="Horizontal" DataContext="{Binding Path=OneCustomer}">
    <Label Content="Last Name:" />
    <TextBox x:Name="LastName" Text="{Binding LastName}" />
</StackPanel>
<Button Content="Load Data" x:Name="Load" />
<Button Content="Save" x:Name="SaveChanges"  />
<DataGrid x:Name="AllCustomers" />

谢谢您的提前帮助。

2个回答

5
使用Caliburn.Micro,我想了解将EF4实体公开为ViewModel属性的利弊(这是在此处和此处讨论的技术)。
我不确定利弊,但我可以告诉您两种方法都被使用。例如,以简单的登录屏幕为例,通常我会将用户名放在ViewModel的属性中,但在表单更复杂的情况下,ViewModel可以聚合其他ViewModel(显示模型)来完成相同的事情。CM对利弊的影响不大,因为它更多地是一个关于MVVM的问题,即有什么利弊。CM将帮助您绑定到两者。
  • 如果您在ViewModel上有一个名为CustomerName的属性,请将TextBox命名为x:name =“ CustomerName”。
  • 如果您在ViewModel上有一个类Customer的实例属性,请将TextBox命名为x:name =“ Customer_Name”,CM将处理绑定。
所以从您的xaml上面:
 <TextBox x:Name="LastName" Text="{Binding LastName}" />

您不需要在StackPanel上设置DataContext。相反:

<TextBox x:Name="OneCustomer_LastName"/>

一个可以使绑定到DataForms和DataGrids更容易的方法是创建显示模型来表示数据在屏幕上的呈现方式。

这是我的观点,但我个人永远不会直接绑定到EF/Linq实体。相反,我会创建一个显示模型来表示该实体以及我想要它显示的方式,并使用AutoMapper进行映射。在许多情况下,这是一对一的映射。这可能看起来是浪费时间,但它具有优点,特别是在更复杂的数据模型布局中,显示模型允许您为显示目的展开数据并将属性属性化以进行验证,而无需将它们粘贴到数据模型实体上。有关更多信息,请查看ASP.NET MVC in Action书中的相关章节。


这是很棒的信息。特别是CM约定将下划线解释为点符号的方式。我一定会去了解AutoMapper和MVC书籍。不过有一个小问题...实体属性应该在setter中更新(到value),还是等到点击保存时一次性更新所有属性?再次感谢。 - DeveloperDan
您是在询问何时将更改持久化到数据库,是当属性值更改还是当用户点击保存时? - Derek Beattie
不,我会坚持保存(粗糙而不啰嗦的规则)。我的想法是,如果我不暴露实体,我可以等到保存时更新所有实体属性。但现在我想想,这没有意义,因为即使只更改了一个值,我也必须更新所有值。所以,我已经回答了自己的问题 - 我将保留实体属性/字段更新在setter中。 - DeveloperDan
@DerekBeattie 我知道这是一个老问题,但我现在也在学习,并且对于您建议使用显示模型,然后使用AutoMapper从EF实体映射到显示模型的建议有疑问。我认为通过使用这种方法,您将失去视图之间的双向数据绑定优势,例如TextBox.Text属性和模型上的属性。如果用户在文本框中输入,我希望数据会自动更新到模型上。难道Automapper会妨碍这一点吗? - Sean
通过一个ajax调用或其他什么方式?这个答案可能有点过时了。 - Derek Beattie

3

既然暴露实体有其他优点(例如通过属性进行验证),我个人会直接暴露它们。

但是我想应该说“这取决于具体情况”,因为总会存在一些缺点(主要是架构上的)。

顺便说一句:你可以将文本框命名为“OneCustomer_LastName”,C.M的约定绑定会起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接