views:

119

answers:

4

So I have an almost 1:1 ratio of views to view models and things seem to be going well. If I understand their purpose correctly it seems that view models should

  1. "Strip down" Entity models so that only relevant properties are passed to the presentation layer
  2. Add additional information needed for presentation such as a list of state abbreviations or contact types when creating, say, an address.

In trying to keep with those principles I've sort of hit a bit of a wall with my Reports controller. Various reports that are generated for a customer require access to about 30 or so different properties. As such, my view model ends up looking very similar to my Entity model.

Of course the easiest solution is to just pass the Entity model to the view so that I'll have access to all properties, however I also need to be able to generate reports for blank or "incomplete" customers. This causes problems will null reference exceptions when trying to access navigation properties on my Entity models.

So I can either use a null check on just about every field within the view, which doesn't seem too appealing... OR I could implement a view model to avoid the null reference exceptions. The problem is that I'd end up with a view model that looked like this:

var customer = customersRepository.GetCustomer(id);
var viewModel = new CustomersViewModel()
{
    FirstName = customer.FirstName,
    LastName = customer.LastName,
    Address = customer.MailingAddress.Address,
    City = customer.MailingAddress.City,
    // and on and on for about 30 different properties
};
return View(viewModel);

Typing all those properties out is one of those things that just feels wrong. Am I missing a more elegant solution to this problem?

+2  A: 

Typing all those properties out is one of those things that just feels wrong

To which ever level you would want to take, eventually you'll have to type all.

So, I see this approach as equally ok.

KMan
+6  A: 

The problem is that I'd end up with a view model that looked like this

AutoMapper is a must to avoid writing exactly the code you posted. I would also recommend you watching the excellent put your controllers on a diet video from the creator of AutoMapper. After watching this video (and a bit of an effort from your side) your controller action will be reduced to a pretty one liner.

Darin Dimitrov
+1 on Automapper, I've found its invaluable for this sort of Domain Model > View Model mapping.
Matthew Abbott
Thank you! It's always nice to find a perfect fitting solution.
Terminal Frost
+3  A: 

You should definitely look into AutoMapper ( http://automapper.codeplex.com/ ).

AutoMapper.Mapper.CreateMap(typeof(CustomersModel), typeof(CustomersViewModel));

AutoMapper.Mapper.CreateMap<CoolObject, CoolObjectViewModel>()
    .ForMember(d => d.Property1, f => f.MapFrom(s => s.Property1))
    .ForMember(d => d.Property2, f => f.MapFrom(s => s.Property2))
    .ForMember(d => d.Property3, f => f.MapFrom(s => s.Property3));
BuildStarted
Hmm...sure would be nice if it told me earlier that answers were added.
BuildStarted
+1 `CoolObject` and code sample
David
A: 

I really dont get what you are trying to achieve here.. there is nothing wrong in writing more code.. it doesnt matter what the size of you code is so long as it is concrete and well organised. what you should be worrying is how do you reduce database interactions, retrieve only required properties from the db.

as your code shows you retrieve the entire customer object and then end up displaying some properties why dont you retrieve only the properties that you need.

also if you are using the properties of Mailing address why dont you pass the entire mailingaddres object as a property why are you splitting up into other properties.

My concern was all the code that was in the controller. It appears that Automapper addresses this very issue. What would you suggest in place of getting a Customer object from the repository? It would seem wrong to return view models from the repository since the domain model should be ignorant of the presentation layer.
Terminal Frost