8

I have EF 4 implemented in the project. Within it, there are tables customer and order. Which has relationship one (customer) to many (order).

I'm creating a viewmodel for both (CustomerViewModel and OrderViewModel) to be passed from my domain layer to interface layer (MVC in this case).

Now the question is "do I need to reference both viewmodel? for example in customerviewmodel has IEnumerable<OrderViewModel> and in orderviewmodel has CustomerViewModel. If so how do I design it (as a best practice) so that IEnumerable<OrderViewModel> and CustomerViewModel is populated with the correct reference?

Phil
  • 42,255
  • 9
  • 100
  • 100
user384080
  • 4,576
  • 15
  • 64
  • 96

1 Answers1

29

I would always drive the design of ViewModels with the specific view in mind, never from the viewpoint of the domain model (= the entities). How a ViewModel looks depends on what you want to display and what you want to modify in a view.

As a result you don't have THE OrderViewModel and THE CustomerViewModel because you have different views which will display or edit an order or customer or parts of these. So, you have those ViewModels for a specific purpose and view and therefore multiple times in different variations.

Suppose, you have an OrderEditView and this view will allow to edit order information and display the customer of that order. You would have an OrderEditViewModel like this:

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; }
    // ...
}

This OrderEditCustomerViewModel doesn't need a reference to the OrderEditViewModel.

You can populate this ViewModel like so:

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();

On the other hand, if you have a CustomerEditView which allows editing customer information and displays the orders of the customer in a list, the ViewModel might be:

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; }
    // ...
}

Here CustomerEditOrderViewModel doesn't need a reference to the CustomerEditViewModel and you can create the ViewModel from the database this way for example:

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();

The Customer(*)ViewModels and the Order(*)ViewModels are different - regarding the necessary references, the properties and the data annotations, depending on the view where they are used.

With these considerations in mind the question for mutual correct references between the OrderViewModel and the CustomerViewModel disappears because you normally don't need such a bidirectional reference for your views.

Slauma
  • 175,098
  • 59
  • 401
  • 420
  • Slauma.. How do you do the mapping between viewmodel to the EF entity and vice versa? – user384080 Apr 10 '12 at 05:28
  • also.. how do you populate public IEnumerable Orders { get; set; } in the CustomerEditViewModel? do you do lazy or eager? – user384080 Apr 10 '12 at 05:46
  • @user384080: The mapping from EF entity to ViewModel are the two code snippets with the `Select` (it's called "projection" and neither lazy nor eager loading, but closer to eager loading except that you only retrieve the columns from the DB which are really needed for the ViewModel, not the full entity which would be unnecessary overhead). Especially the last snippet also populates the `Orders` collection (see the inner `Select`). For the way back from ViewModel to entity I use DTOs, you can manually map the properties from ViewModel to DTO or use a tool like AutoMapper. – Slauma Apr 10 '12 at 12:44
  • @user384080: I've asked a similar question some time ago, maybe it helps: http://stackoverflow.com/questions/5995140/models-viewmodels-dtos-in-mvc-3-application – Slauma Apr 10 '12 at 12:48