Recursos, mensajes de excepción y otras cadenas…..

Bueno, imagino que después de leer el título le quedará bastante claro de lo que vamos a hablar en este pequeño post. A lo largo de este tiempo he visto muchas y diversas formas de manejar los típicos mensajes de excepción y otros elementos localizables de nuestro código ( sin hablar nada de UI en este caso ), unas mejores y otras peores. Con la llegada de .NET y los recursos incrustados, muchos de los inconvenientes tradicionales que teníamos se vieron resueltos. Elementos como el fallback en la resolución de la cultura, los conceptos de culturas específicas y neutras, sin duda, facilitaron enormemente nuestro trabajo. El consumo de estos recursos incrustados de .NET, por regla general, se realiza utilizando las propiedades de la clase que se nos genera automáticamente por cada uno los archivos de recursos [ recuerde que por defecto estos ficheros tienen asociada una custom tool, ResXFileCodeGenerator, para la generación de esta clase ]. Elementos habituales podrían ser, algunos como los siguientes:

 

 

 

Alguno de los problemas con esta forma de trabajo surge por ejemplo cuando queremos hacer estos mensajes parametrizados, puesto que tendríamos que recurrir a cosas como la siguiente:

 

Cuando se utiliza esta entrada de recursos, no hay más remedio que acudir a nuestro mensaje para descubrir si este toma parámetros o no y establecerlos en caso necesario, por no hablar de que la legibilidad podría verse afectada, sin duda. Mecanismos para intentar solventar estos problemas hay muchos y variados pero uno que últimamente me ha gustado y que he seguido ha sido el utilizado por el equipo de EF para hacer la gestión de esta problemática. Mecanismo que se basa en una sencilla plantilla .tt  junto a un fichero de recursos que nos permite generar 2 clases fundamentales Strings y Error preparadas para ser utilizadas en el código de una forma más simple y legible que mediante el código por defecto de ResXFileCodeGenerator. De entre algunas de las características que incorpora esta plantilla podemos ver que expone en forma de parámetros los parámetros de las entradas del archivo de recursos, de tal forma que si, por ejemplo, tenemos una entrada con valor “any message for {0} and {1}”  esta plantilla nos expondrá en nuestra clase Strings un método similar a lo siguiente:

 

 

Con lo cual, el uso anterior de esta clave de recurso podría realizarse como, por ejemplo de la siguiente manera:

 

 

La parte de Error, es quizás, más interesante todavía, puesto que nos permite generar a partir de los claves de nuestros ficheros de recurso métodos que devuelvan las excepciónes que necesitemos, cuyos tipos se extraen además del mismo archivo de recursos gracias a un pequeño trick con el campo comentarios, puesto que interpretan comentarios como ## ExceptionType=InvalidOperationException como la necesidad de generar un método que devuelva una excepción InvalidOperationException con el mensaje de la misma entrada del recurso. A continuación podemos ver un ejemplo de uno de los mensajes de Error que tenemos en el código de EF

 

 

 

Bueno, amigo lector, le invito desde aquí a revisar como otros resuelven problemas habituales en nuestro trabajo. En este caso, esta plantilla de la que acabamos de ver es un ejemplo bastante simple de tratar el problema. Aunque hay que tocar un par de cosas para que la misma se pueda utilizar en cualquier proyecto la verdad es que es terriblemente sencilla, por lo que le invito a probarla…

 

Saludos

Unai

EF Agregando configuraciones de forma automática

Hay ciertas situaciones en las que las convenciones de EF para nuestros mapeos de entidades no nos sirven o bien no nos sirven completamente, un ejemplo de esto es cuando trabajamos con una base de datos existente, dónde, seguramente, la convención del nombre de las tablas ( pluralización en inglés de los nombres de las entidades ) no nos sirva, y así con otras muchas convenciones. En estas situaciones, es más que seguro que tengamos que hacer uso de las configuraciones personalizadas, instancias de EntityTypeConfiguration<> y ComplexTypeConfiguration<>En estos casos, cuando el modelo es grande, el aspecto que tendrá nuestro OnModelCreating será un poco esperpéntico, algo similar a lo siguiente:

 

 

El problema de este tipo de códigos, amén del matenimiento, es la poca legibilidad del mismo, donde por ejemplo, nos costaría encontrar si una entidad está o no mapeada. Solventar este problema y hacer un código más legible y facilitar la vida al desarrollador no es difícil,  ya que en realidad lo único que estamos haciendo ahí es configurar todas las clases de un determinado tipo, algo por lo tanto muy fácil de automatizar. En el siguiente repositorio de GitHub he implementado una posible solución para estos problemas, que nos permite cambiar este código anterior por algo como lo siguiente:

 

o, si tenemos los mapas de configuración en otro ensamblado, podríamos hacer:

 

Espero que os guste y, sobre todo, que os sea de utilidad…

EF 6 Alpha: Custom Conventions

El tema de las convenciones personalizadas para el modelo de Code First sin duda ha sido una de las cosas que más echamos de menos en EF, de hecho, durante alguna de las betas estas posibilidades estaban incluidas como en su día vimos en algún post. De entre las distintas novedades de esta versión preliminar de EF 6 podemos destacar la vuelta al ruedo de estas features, aunque ahora con una implementación, en mi opinión, mucho más acertada. A lo largo de la siguiente entrada intentaremos darle un vistazo a estas nuevas posibilidades, si lo desea, también puede leer el walkthough que el equipo de ADO.NET tiene sobre este tema.

Introducción

 

Todas las convenciones de EF, están basadas en la siguiente interface, IConfigurationConvention:

Esta interface, como observará tiene dos parámetros genéricos TMemberInfo y TConfiguration, que nos permite establecer, por un lado con TMemberInfo si la configuración es para un tipo o para una propiedad y en ultimo lugar a que elemento en concreto se aplica, para el caso de las propiedades ConfigurationBase tiene un jerarquía similar a esta:

 

ConfigurationBase

  -> Property Configuration

->NavigationPropertyConfiguration

->PrimitivePropertyConfiguraiton

    -> BinaryPropertyConfiguraiton

    -> DateTimePropertyConfiguration

     -> ….

Dicho esto, para crear por ejemplo una convención que afecte a propiedades de tipo DateTime tendríamos que implementar una clase como la siguiente:

Por supuesto, dentro del método Apply tendríamos que establecer que queremos en la convención, si se fija, el delegado configuration nos permite obtener la configuración actual de esa propiedad, con lo cual, podríamos ver/modificar la misma. En este caso optaremos por hacer lo mismo que el el walkthoug, puesto que me parece muy ‘real’ el hecho de adaptar el tipo de datos en Sql Server a datetime2 para estas propiedades.

 

Por supuesto, usted puede revisar el miembro memberInfo para decidir a que propiedades se aplica, por ejemplo, le podría interesar solo aplicar esta convención a las propiedades cuyo nombre por ejemplo acaben con un postfijo determinado, aunque esto, en mi humilde opinión no es algo que me guste para nada. Las convenciones a nivel de entidad, son prácticamente iguales, con la salvedad de que lógicamente configuran aspectos de la entidad y no de las propiedades, por ejemplo, la convención de que la propiedad Id sea la clave primaria de una entidad podría haberse escrito así.

 

Bien, una vez que tenemos definidas nuestras convenciones, para agregarla usaremos la propiedad Conventions, que ya es conocida de nuestros DbContext, con la diferencia que ahora dispone de métodos para incluir convenciones y no solamente para eliminarlas. De hecho, incluso me permite establecer el orden de ejecución de las mismas.

 

 

Con el fin de simplificarnos la vida, el equipo de ADO.NET nos ha creado una pequeña clase LightweigtConvention con la cual podremos establecer convenciones sin necesidad de escribir una nueva clase para las mismas. Esta clase no es más que una implementación de IConventionConfiguration para tipos y propiedades que hace uso de una clase, EntityConventionConfiguration para agregar convenciones mediante un API fluent.

Utilizando esta clase, por lo tanto, podríamos crear una convención tal y como sigue:

 

Puede observar como el trabajo a realizar depende de si configura propiedad o entidad y este está representado por las clases LightweighPropertyConfiguration o LightweighEntityConfiguration.

 

Bien, pero ¿y si quiero hacer las convenciones con atributos? Pues sencillo, en vez de implementar IConfigurationConvention trabajaremos con AttributeConfigurationConvention, el cual, nos permite indicar que atributo es el que será el atributo marcador, es decir aquel atributo que EF revisará para saber que tiene que aplicar una convención. Para verlo, utilizaremos también el del walkthoug, puesto que al igual que con el DateTime es también bastante habitual. En este ejemplo el objetivo es poder disponer de un atributo, por ejemplo NonUnicodeAttribute que nos permita decorar a las propiedades como no unicode. Pues bien, este atributo será un atributo marcador, es decir, no necesita código de trabajo con EF, por ejemplo igual que así:

 

Bien, ahora que tenemos creado el atributo marcador, solamente tenemos que aplicarle la convención ,tal cual podríamos hacer antes con nuestras PrimitivePropertyConfiguration…

 

Sencillo ¿verdad?…Bueno, espero poder publicar alguna entrada más sobre EF 6, de hecho hay un par de novedades que me parecen super interesantes.. y me gustaría también sacar algo de tiempo para colaborar un poco con el código, a ver si lo logro…

 

Saludos

Unai