Models for a view (some objects are more equal than others) | Peter van Ooijen

:

How to implement the V and the C in MVC is no point of great discussion. When it comes to the M the variation increases. An ASP.NET MVC app has a Models folder; what you will find in there varies among the many samples found. The folder looks a bit like a dumping place for the author’s favorite technology, be it EF, sql data adapters, web-services, domain objects, pure agnostic view models or whatever else comes into imagination.

In this post I will explore a little bit what kind of models to use. In case you consider the only just solution a pure view model, as presented in MVVM (model View ViewModel), you do have a valid best practice. Read on nevertheless for reasons why that’s good. Models based explicitly on an technology like ado.net are a bad practice, that is beyond discussion. Left in the middle are things like domain-objects. Mapped (FI) by nHibernate to a sql database and served to your app through repositories. To your app these objects are plain objects (POCO’s), at first sight not hindered by any underlying technology. In a real app they do have some behavior, lazy loading being only one aspect of that, which might fire back.

Can you use such a mapped domain object in a View ? As said, the best practice is to wrap up the object in a ViewModel. With a different model for every view. In real life not everybody does that. It can be tedious and a maintenance nightmare. In quite a number of cases we do use domain objects in our views. Which does work provided you treat them with care.

When presenting data lazy loading sticks up it’s head. It will fire when the view is actually rendered. Which happens after the controller action has completed. As long as the session to the database is still available that will work. I spent my last post on that.

When updating a domain object from posted data real danger emerges. I’ve seen very poisonous recipes (pun again intended) doing that. They boil down to the following snippet. There is a DO Patient, in the view a patient’s data has been edited and is now posted back to the controller to be persisted to the database.

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Patient(Patient patient)

{

    Repository.Persist(patient);

    return PartialView(patient);

}

What will happen is that the MVC routing will find a match for the controller action. It will create a new patient object and populate that with the form’s data. Also when the data belonged to a existing patient. The original sample contained some fiddling to try to restore that. But that should not be the way, deep down below you are messing with nHibernates’s deep inner workings. Something you would rather stay on good terms with.

There is a neat way out. Change your action to the following

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Patient(int patientId, FormCollection form)

{

    var patient = patientId == 0 ? Repository.New() : Repository.Get(patientId);

    TryUpdateModel(patient);

    Repository.Persist(patient);

    return PartialView();

}

The controller is now “aware” of an identifying Id of the DO. Which is going to be part of the route parameters of the form

using (Ajax.BeginForm(“Patient”, “Patient”, new { patientId = Model.Id }, new AjaxOptions { UpdateTargetId = “patientnaw” }))

        {

When posting back the routing will hit our action. Which now has the Id to get the (new) patient’s data from the repository. TryUpdateModel then updates the patient from the posted back formdata in the second parameter, after which the patient can be persisted. In your real app you should of course check the result of TryUpdateModel and do some real validation. For now that is beyond the scope of this post.

What should be clear is that it is a one way street, the DO’s can flow from controller to the view, but don’t ever expect the view to post back a real DO. Whether to work with only pure, really agnostic, ViewModels or nevertheless to use DO’s straight from the repository is up to you. I hope to have shown you some of the pitfalls, and a way out, of doing the latter.