2012-03-27 39 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