Validacion de modelos a nivel de clases con EF Code First y ASP.NET MVC 3

Hace poco el equipo de datos publicó la CTP 5 de la nueva librería Entity Framework Code-First.

En el post que escribí hablé de algunas mejoras que se han introducido en esta CTP 5. El soporte automático de ejecución de las DataAnnotations en las propiedades de los modelos fué una de las características de las que hablé. Ofrece una forma realmente fácil de habilitar la validación de propiedades en nuestro modelo.

Podemos aplicar atributos de validación como [Required], [Range] y [RegularExpression] - todas ellas están incluidas en .NET 4 - a nuestras clases del modelo para asegurar que las propiedades del modelo son válidas hasta que se persisten en la base de datos. También podemos crear nuestros propios atributos de validación (como este increible validador de tarjetas de crédito)  y hacer que se apliquen automáticamente por EF Code First. Esto ofrece una forma fácil de validar los valores de las propiedades de nuestro modelo. Ya vimos algunos ejemplos de esto en mi post anterior.

Validación de modelo a nivel de clase usando IValidatableObject

Los atributos DataAnnotation ofrecen una forma fácil de validar propiedades individuales en las clases de nuestro modelo.

Mucha gente me ha preguntado -"¿EF Code First soporta también alguna manera de implementar métodos de validación a nivel de clases en los objetos del modelo, para reglas de validacion que necesitan consultar varias propiedades?" Pues si - y lo podemos hacer muy fácilmente implementando la interfaz IValidatableObject en nuestro modelo.

Método IValidatableObject.Validate()

Aquí tenéis un ejemplo del uso de la interfaz IValidatableObject (que viene en .NET 4 en el namespace System.ComponentModel.DataAnnotations) para implementar dos reglas personalizadas sobre la clase Product. Estas dos reglas se aseguran de:

  • Nuevas unidades no pueden ordenarse si el producto está en el estado disconinuado.
  • Nuevas unidades no pueden ordenarse si hay más de 100 unidades en stock.

Aseguraremos que estas reglas de negocio se cumplan implementando la interfaz IValidatableObject en nuestra clase Product, implementendo el método Validate() de la siguiente manera:

El método IValidatableObject.Validate() puede aplicar reglas de validación sobre varias propiedades, y puede mostrar varios mensajes de error. Cada valor ValidationResult devuelto puede tener tanto un error como una lista de nombres de propiedades que provocaron el error de validacion (es muy util para mostrar mensajes de error en la interfaz de usuario).

Aplicación automática de validaciones

EF Code First (desde esta CTP 5) llama automáticamente al método Validate cuando un objeto del modelo que implementa la interfaz IValidatableObject es guardado. No tenemos que escribir ningún código para que esto ocurra - esto está soportado ahora por defecto.

Este nuevo soporte significa que el código siguiente - que viola una de las reglas de negocio - se aplicarán automáticamente lanzando una excepción (y se suspenderá la transacción) cuando llamemos al método SaveChanges() de nuestro DbContext Northwind:

Además de manejar las excepciones de validación de forma reactiva, EF Code First nos permite comprobar proactivamente los errores de validación. A partir de la CTP 5, podemos llamar al método GetValidationErrors() de la clase DbContext y obtener una lista de errores de validación de los objetos del modelo con el que estamos trabajando. GetValidationErrors() nos dará una lista de todos los errores de validación - estén generados o no por atributos Dataannotations o por la implementación del método IValidateObject.Validate().

Aquí tenéis un ejemplo de cómo usar el método GetValidationErrors() para comprobar (y manejar) los errores ántes de llamar al método SaveChanges():

ASP.NET MVC 3 y IValidatableObject

ASP.NET MVC 2 incluía el soporte para aplicar los atributos de DataAnnotations en los objetos del modelo que se usan en la infraestructura de modelos de ASP.NET MVC. ASP.NET MVC 3 va más hallá y también soporta la interfaz IValidatableObject. Este soporte combinado para la validación de modelos hace realmente fácil mostrar los mensajes de error adecuados cuando ocurran los errores de validación.

Para ver esto en acción, consideremos un formulario simple de Creación que permita a los usuarios crear un nuevo producto:

Podemos implementar la funcionalidad de creación anterior usando una clase ProductsController con dos métodos de acción "Create" como los siguientes:

El primer método Create() implementa una versión para la url /Products/Create que se encarga de las peticiones HTTP-GET - y muestra el formulario HTML que lo rellena. El segundo método Create implementa una versión para la url /Products/Create para las peticiones HTTP-POST - y que toma los datos del formulario, asegura que es válido, y si es válido lo guarda en la base de datos. Si ocurre algún problema de validación se vuelve a mostrar el formulario con los valores que se pusieron.

La plantilla de vista razor de nuestra vista "Create" (que renderiza el formulario) es como el siguiente:

Una de las cosas buenas sobre la implementación anterior Controlador+Vista es que no tenemos que escribir ninguna lógica de validación para ella. La lógica de validación y las reglas de negocio se implementan totalmente en la capa de modelo, y la clase ProductsController sólo comprueba cuando es válido (llamando al helper method ModelState.IsValid) para determinar si intentamos guardar los cambios o mostrar el formulario con los errores. Las llamadas al método Html.ValidationMessageFor() en nuestras vistas muestran los mensajes de validacion que no se cumplen por las DataAnnotations y el método IValidatableObject.Validate().

Podemos ver el escenario anterior en acción rellenando el formulario con datos que van a hacer que se muestren estos errores:

Fijáos cómo cuando hacemos clic en el botón "Create" tenemos el mensaje de error. Esto es porque marcamos el checkbos "Discontinued" y hemos puesto un valor en UnitsOnOrder (de manera que no se cumplen  nuestras reglas de negocio).

Os estaréis preguntando - ¿cómo hizo ASP.NET MVC para destacar el mensaje de error al lado del textbox UnitsOnOrder?. Lo hizo porque ASP.NET MVC 3 aplica la interfaz IValidatableObject cuando realiza el binding del modelo, y obtiene los mensajes de error de las validaciones que han fallado.

La regla de negocio de la clase del modelo Product indica que la propiedad "UnitOnOrder" debe resaltarse cuando no se cumple la regla:

El método Html.ValidationMessageFor() sabe mostrar mensajes de errores de validación (al lado del textbox UnitsOnOrder) por el nombre de la propiedad que le hemos indicado:

Mantener las cosas DRY

ASP.NET MVC y EF Code First nos permiten mantener las validaciones y las reglas de negocio en un solo lugar (en la capa de modelo), evitando así tener que ponerlo en nuestros Controladores y Vistas.

Mantener la lógica de validación en la capa de modelo nos ayuda a no duplicar validaciones/reglas de negocio a medida que añadimos Controladores y Vistas a nuestra aplicación. Nos permite cambiar rápidamente nuestra lógica de negocio y validaciones en un sólo sitio (en la capa de modelo) - y tener controladores y vistas en nuestra aplicación en las que se aplican automáticamente. Esto nos ayuda a mantener el código de nuestra aplicación mas limpio y mantenible, y hace mucho más fácil de evolucionar y actualizar nuestra aplicación en el futuro.

Resúmen

EF Code First (a partir de la CTP 5)  incluye el soporte para DataAnnotations y la interfaz IValidatableObject. Esto nos permite añadir validaciones y relgas de negocio a nuestros modelos, y hacer que EF se asegure de que se cumplen cada vez que se intenta persistir los cambios en la base de datos.

ASP.NET MVC 3 también soporta las DataAnnotations y IValidatableObject, haciendo que sea aún más facil usarlas con el modelo de EF Code First - y conseguir que los controladores y vistas en la capa web apliquen estas reglas. Esto hace más facil crear aplciaciones limpias y mantenibles.

No tenemos que usar DataAnnotations o la interfaz IValidatable Object para aplicar nuestras reglas de validación/negocio. Siempre podemos crear nuestra arquitectura de validación y/o usar frameworks/patrones más avanzados si queremos. Pero para la mayoría de aplciaciones este soporte es suficiente - y ofrecen una forma muy productiva de crear soluciones.

Espero que sirva.

Scott.

Traducido por: Juan María Laó Ramos.

Artículo original

4 pensamientos en “Validacion de modelos a nivel de clases con EF Code First y ASP.NET MVC 3

  1. Pingback: VS 2010 SP1 y SQL CE « Thinking in .NET

  2. Pingback: Releases de ASP.NET MVC 3, IIS Express, SQL CE 4, Web Farm Framework, Orchard, WebMatrix « Thinking in .NET

Deja un comentario