我总是会在设计 ViewModel 时考虑到特定的视图,而不是从领域模型(=实体)的角度出发。 ViewModel 的外观取决于您要在视图中显示的内容以及要修改的内容。
因此,您没有 THE OrderViewModel 和 THE CustomerViewModel,因为您有不同的视图来显示或编辑订单或客户或其中的一部分。因此,您将这些 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。
你可以像这样填充这个 ViewModel:
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 允许编辑客户信息并在列表中显示客户的订单,则 ViewModel 可能是:
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,您可以通过这种方式从数据库创建 ViewModel,例如:
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(*)ViewModels 和 Order(*)ViewModels 是不同的 - 关于必要的引用、属性和数据注释,取决于使用它们的视图。
考虑到这些考虑,OrderViewModel 和 CustomerViewModel 之间相互正确引用的问题消失了,因为您通常不需要为您的视图提供这样的双向引用。