2012-03-27 38 views
7

我在项目中实现了EF 4。其中,有客户和订单表。这与一个(客户)与多个(订单)有关系。如何设计ViewModel

我创建两个(CustomerViewModel和OrderViewModel)一个视图模型,从我的域名层传递到界面层(MVC在这种情况下)。

现在的问题是“我是否需要同时引用视图模型?例如在customerviewmodel有IEnumerable<OrderViewModel>和orderviewmodel具有CustomerViewModel。如果让我怎么设计它(作为最佳实践),这样IEnumerable<OrderViewModel>CustomerViewModel填充了正确的参考?

+0

看看这是否有帮助:http://blogs.teamb.com/craigstuntz/2009/12/31/38500/ – 2012-03-27 12:41:09

+0

抱歉不相关.. – user384080 2012-03-29 08:54:50

回答

23

我总是推动ViewModel的设计,考虑到特定的视图,从来没有从领域模型(=实体)的角度来看ViewModel的外观取决于你想要展示什么以及什么你想在一个视图中进行修改。

因此,你没有OrderViewModelCustomerViewModel,因为您有不同的视图,这将显示或编辑订单或客户或其中的一部分。因此,您将这些ViewModel用于特定目的和视图,因此可以多次使用不同的变体。

假设你有一个OrderEditView这种观点将允许编辑订单信息,并显示该订单的客户。您将有一个OrderEditViewModel这样的:

public class OrderEditViewModel 
{ 
    public int OrderId { get; set; } 

    public DateTime? ShippingDate { get; set; } 

    [StringLength(500)] 
    public string Remark { get; set; } 
    //... 

    public OrderEditCustomerViewModel Customer { get; set; } 
} 

public class OrderEditCustomerViewModel 
{ 
    [ReadOnly(true)] 
    public string Name { get; set; } 

    [ReadOnly(true)] 
    public string City { get; set; } 
    // ... 
} 

OrderEditCustomerViewModel不需要的OrderEditViewModel参考。

可以填充这个视图模型像这样:

var orderEditViewModel = context.Orders 
    .Where(o => o.OrderId == 5) 
    .Select(o => new OrderEditViewModel 
    { 
     OrderId = o.OrderId, 
     ShippingDate = o.ShippingDate, 
     Remark = o.Remark, 
     Customer = new OrderEditCustomerViewModel 
     { 
      Name = o.Customer.Name, 
      City = o.Customer.City 
     } 
    }) 
    .SingleOrDefault(); 

在另一方面,如果你有一个CustomerEditView允许编辑的客户信息,并显示在列表中的客户的订单,视图模型可能是:

public class CustomerEditViewModel 
{ 
    public int CustomerId { get; set; } 

    [Required, StringLength(50)] 
    public string Name { get; set; } 

    [Required, StringLength(50)] 
    public string City { get; set; } 
    //... 

    public IEnumerable<CustomerEditOrderViewModel> Orders { get; set; } 
} 

public class CustomerEditOrderViewModel 
{ 
    [ReadOnly(true)] 
    public DateTime? ShippingDate { get; set; } 

    [ReadOnly(true)] 
    public string Remark { get; set; } 
    // ... 
} 

这里CustomerEditOrderViewModel不需要的CustomerEditViewModel一个参考,你可以从数据库中创建视图模型这种方式,例如:

var customerEditViewModel = context.Customers 
    .Where(c => c.CustomerId == 8) 
    .Select(c => new CustomerEditViewModel 
    { 
     CustomerId = c.CustomerId, 
     Name = c.Name, 
     City = c.City, 
     Orders = c.Orders.Select(o => new CustomerEditOrderViewModel 
     { 
      ShippingDate = o.ShippingDate, 
      Remark = o.Remark 
     }) 
    }) 
    .SingleOrDefault(); 

Customer(*)ViewModel s和Order(*)ViewModel s是不同的 - 关于必要的参考,属性和数据注释,取决于它们在何处使用。

考虑到这些因素,OrderViewModelCustomerViewModel之间的相互正确引用的问题消失了,因为您通常不需要这种视图的双向引用。

+0

Slauma ..你如何做viewmodel之间的映射EF实体反之亦然? – user384080 2012-04-10 05:28:49

+0

也..如何填充公共IEnumerable 订单{获取;组;在CustomerEditViewModel中?你做懒惰还是渴望? – user384080 2012-04-10 05:46:32

+0

@ user384080:从EF实体到ViewModel的映射是带有“Select”的两个代码片段(它被称为“投影”,既不懒惰也不渴望加载,但更接近急切加载,除非您只从DB中检索列对于ViewModel来说确实是需要的,而不是完全的实体,这将是不必要的开销)。特别是最后一个片段也会填充Orders集合(请参阅内部的“选择”)。对于从ViewModel返回到实体的方式,我使用DTO,您可以手动将属性从ViewModel映射到DTO或使用像AutoMapper这样的工具。 – Slauma 2012-04-10 12:44:57