ASP. NET MVC: Mapping Entities to View Model
I'm trying to clean up my action methods in an ASP.NET MVC project by making use of view models. Currently, my view models contain entities that might have relationships with other entities. For example, ContactViewModel class might have a Contact, which might have an Address, both of which are separate entities. To query for a list of Contact objects, I might do something like the following.
IList<Contact> contacts;
using (IContactRepository repository = new ContactRepository())
{
contacts = repository.Fetch().ToList();
}
EditContactViewModel vm = new EditContactViewModel(contacts)开发者_运维百科;
return View(vm);
This method brings on a few problems. For example, the repository is queried within a using statement. By the time the view renders, the context has gone out of scope, making it impossible for the view to query the Address associated with the Contact. I could enable eager loading, but I'd rather not. Furthermore, I don't like that the entity model has bled over into my view (I feel like it's a bad idea for my View to have knowledge of the relationship between Contact and Address, but feel free to disagree with me).
I have considered creating a fattened class that contains properties from both the Contact and Address entities. I could then project the Contact and Address entities into my new, flattened object. One of my concerns with this approach is that my action methods may get a little busy and I don't think AutoMapper is able to map two or more objects into a single type.
What technique is/are preferred for overcoming my concerns?
Automapper will work for your case. What you have is an object graph, a thing has some more things, which Automapper handles fine.
Taking these concerns in order...
First, if you are worried about the using statement and the repository (I don't know if it is LINQ-to-SQL or LINQ-to-Entities, but it doesn't matter), what I would recommend you do is implement IDisposable on your Controller, and then store the repository in a field either on the model or in the controller or somewhere where you have access to it in the view (if you need it, if the model has knowledge of it while the object is "alive" then you just need to keep it around for the life of the controller).
Then, when the request is complete, the Dispose method on your controller is called and you can dispose of the repository there.
Personally, I have a method on my base controller class which looks like this:
protected T AddDisposable<T>(T disposable) where T : class, IDisposable
{
// Error checking.
if (disposable == null) throw new ArgumentNullException("disposable");
// Add to list
...
}
Basically, it allows you to store the IDisposable implementations, then in the IDisposable implementation of the controller, it iterates through the list, disposing of everything.
Regarding the exposure of the address on the entity model, I don't see this as a bleed issue, personally. The address is part of the composition of the contact (IMO), so it would be wrong to not have it there.
However, I don't disagree if you don't want it there because you want to focus on one type in one controller at a time, etc, etc.
To that end, you would want to create Data Transfer Objects which basically map between the type you expose in the view model and your entity model.
精彩评论