[ASP.NET MVC] Enlazando varios Modelos a un View

Esta es una situación común cuando estamos trabajando proyectos en el MVC Framework, y hay varias salidas como crear vistas parciales y unirlas en una única vista.

Sin embargo la solución que más me gusta es la de crear un ViewModel propio para cada una de las vistas que lo requiera, en principio puede sonar a mucho trabajo adicional, pero a decir verdad la flexibilidad que ofrece me ha gustado mucho. ¿En qué consiste? Pues simplemente en crear una clase adicional encargada de “unir” nuestras dos entidades de dominio, por ejemplo, supongamos que tengo dos entidades, estas son:

    public class ClassA
    {
        public int Id { get; set; }
        public string PropertyA { get; set; }
    }
    public class ClassB
    {
        public int Id { get; set; }
        public string PropertyB { get; set; }
    }

Ahora quiero crear una página donde pueda registrar datos de estas dos entidades, y es aquí donde crearemos nuestro ViewModel ClassCreateViewModel, una primera aproximación seria:

    public class ClassCreateViewModel
    {
        public ClassA ClassA { get; set; }
        public ClassB ClassB { get; set; }
    }

El controlador…

        public ActionResult Create()
        {
            return View();
        }

Y la vista la generamos sin escribir mucho código (no sé por qué hay gente que le sigue pareciendo improductivo MVC)

Hacemos algunas modificaciones y el código queda así:

@model MvcApplication1.ViewModels.ClassCreateViewModel


<meta name="viewport" content="width=device-width" />
Create

<script type="text/javascript" src="~/Scripts/jquery-1.7.1.min.js"></script><script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
 @using (Html.BeginForm()) {
 @Html.ValidationSummary(true)</pre>
<fieldset><legend>ClassCreateViewModel</legend>
<div class="editor-label">@Html.LabelFor(model => model.ClassA.PropertyA)</div>
<div class="editor-field">@Html.EditorFor(model => model.ClassA.PropertyA)
 @Html.ValidationMessageFor(model => model.ClassA.PropertyA)</div>
<div class="editor-label">@Html.LabelFor(model => model.ClassA.PropertyB)</div>
<div class="editor-field">@Html.EditorFor(model => model.ClassB.PropertyB)
 @Html.ValidationMessageFor(model => model.ClassB.PropertyB)</div>
 <input type="submit" value="Create" /></fieldset>
<pre>
 }</pre>
<div>@Html.ActionLink("Back to List", "Index")</div>
<pre>

Luego desde el controlador simplemente hacemos las asignaciones y separaciones que correspondan.

Consideraciones y opiniones.

Personalmente no me gusta definir los ViewModels así, exponiendo una propiedad del tipo de cada uno de las entidades que quiero “unir”, prefiero crear estos ViewModels de una forma más explícita y poder acudir a beneficios como los DataAnnotations, y modelo y uso lo que realmente necesito sin tener que hacer “maromas” sobre los views para ocultar un campo, sino que con solo acudir a los Scaffold templates ya tenga vistas listas y con la validación que necesito. Entonces una segunda aproximación seria:

    public class ClassCreateViewModel
    {
        [Required]
        [Display(Name="Nombre Usuario")]
        public string PropertyB { get; set; }

        public string PropertyA { get; set; }
    }

Por lo general no me gusta decorar mis entidades de dominio con DataAnnotations, ya que me parece un medio para contaminarlas, si trabajo con EntityFramework prefio usar Fluent Api. Pero la comodidad de dataAnnotations es algo que no tiene ningún costo cuando lo trabajamos con los ViewModels y además nos genera varios beneficios.

Finalmente, y ya para terminar, no quiero que se confundan estos ViewModels con el ViewModel de MVVM, este patrón es más orientado a sistemas basados en eventos (EDP) y la Web no es uno de ellos, o bueno del lado de HTML5 en el cliente sí que se puede y ya hasta hay frameworks que nos ayudan a esto, Pero este no es el caso, todo se hace por el http.

Como siempre, quedo atento a sus comentarios.

Hasta el próximo post.

Anuncios
[ASP.NET MVC] Enlazando varios Modelos a un View

11 comentarios en “[ASP.NET MVC] Enlazando varios Modelos a un View

  1. Anónimo dijo:

    Hola Nico,

    Comentas que no estás haciendo un ViewModels similar al de MVVM, pero creo que estás implementando un patrón muy cercano a él. Donde el VM enlaza lo que es la Vista con el modelo que viene de Servidor…

    Xai Paper

    1. Hola Xavi.

      Si que me he tardado en responder porque no había visto la notificación de tu comentario 😦

      Como yo lo veo, los VM de MVVM son más “inteligentes” y es que están pensados para sistemas EDP, donde la interacción con el View dará como resultado una serie de acciones en el VM, con el tema de los Bindings y los Commands y notificaciones de cambios en las propiedades.

      Los VM para MVC que mostré en el post cumplen con el simple objetivo de ayudarnos con la construcción de la View, pero cada acción realizada, por ejemplo un http post, seguirá siendo controlada por el Controlador y no por el VM, y una vez controlas la petición conviertes el VM al tipo de tu modelo.

      Gracias por comentar.
      Si tienes más opiniones no dudes en comentarlas 😉

      Saludos.

  2. tenes un error en el código de muestra de la vista,,
    @Html.LabelFor(model => “”””model.ClassA.PropertyB””””)
    @Html.EditorFor(model => model.ClassB.PropertyB)
    @Html.ValidationMessageFor(model => model.ClassB.PropertyB)

    la class a no tiene property b

  3. Eric dijo:

    Yo estaba queriendo hacer lo mismo, a partir de dos modelos crear un tercer modelo que los contenga, pero ahora de implementarlo en la vista (necesitaba que se liste como un IEnumerable para uno de ellos) me tiraba un error que decia que “La entidad de tipo “Bla” no era parte del modelo en el contexto actual” eso que lo puse en el DBContext, alguien sabe porque viene el error?

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s