EF Core, de las convenciones a …?

Los que conocéis un poco EF 6.X seguro que sabéis que disponemos de un mecanismo para cambiar las convenciones por defecto a la hora de crear nuestros modelos. Este característica por lo general viene dada por la clase base DbConnection, sobre la cual podemos trabajar para personalizar las convenciones existentes o bien poder poner nuevas convenciones.

Un ejemplo de las posibilidades que esta clase base nos ofrece  se representan en el siguiente ejemplo de código, con una de las típicas convenciones que usamos cuando utilizamos EF 6.X.

 

Este modelo de convenciones es muy potente, aunque también tiene ciertas debilidades. El principal punto débil es que podemos configurar los tipos asignados pero no podemos decir a EF que un determinado tipo CLR o bien alguna determinada propiedad con alguna característica concreta se mapeará de una determinada manera en la base de datos. Seguro que ahora mismo está un poco confundido con el párrafo anterior, puesto que precisamente el ejemplo que acabamos de poner mapea las propiedades de tipo DateTime a DateTime2, entonces. Pues bien, esto funciona porque este tipo de datos datetime2 es conocido por EF, pero ¿que pasa si asignamos una propiedad a una columna de la cual no hay soporte, como por ejemplo XML? La respuesta es que esto no funcionará.

En EF Core 1.1, al contrario que en EF 6.X no tiene un API de primer nivel para el trabajo de convenciones.  Suponemos que algún futuro no muy lejano este API de primer nivel será creado, bien directamente por el equipo de trabajo de Entity Framework Core o bien por diferentes contribuciones de la comunidad. Sin embargo, si tiene abstracciones de base que nos darán mucha potencia y que veremos a continuación.

Si trabajamos con Sql Server, de manera idéntica tendremos este mecanismo con otros proveedores, tenemos una implementación de un RelationalTypeMapper que nos permitirá tener soporte para jugar con ciertos elementos convencionales o la modificación de como ciertas propiedades se mapean a nuestros elementos relacionales.

A continuación veremos un pequeño ejemplo en el que no solamente podemos configurar el tamaño por defecto de nuestras cadenas de caracteres sino también la longitud de los parámetros de las consultas.

 

Usar este nuevo mapper es relativamente sencillo, una de las cosas que tenemos en EF Core gracias a la utilización del sistema de dependencias por defecto está precisamente en la facilidad que tenemos para cambiar ciertos componentes por otros.

 

Hay otros muchos ejemplos de personalizaciones de esta clase, como por ejemplo la comentada anteriormente para la asignación de un tipo. Para no repetir código que ya está publicado y accesible mostraremos este ejemplo sacando el mismo del repositorio de Rowan Miller, uno de los PM de EF Core. El mismo puedes localizarlo aquí.

 

Del código anterior fíjese como podemos crear nuestro propio RelationalTypeMapping asignando en el tanto el tipo CLR como el tipo en el modelo  relacional subyacente. Es verdad que aún no tenemos las API de primer nivel, pero si tenemos las bases que permitirán su construcción o bien su uso directo, aunque no sea tan simple como debería.

 

Saludos

Unai

 

 

 

Shadow Properties – Otros ejemplos de uso

La verdad es que ya llevo unas cuantas charlas encima sobre EF Core 1.1 en las que trato de hacer un repaso por encima de las diferentes características nuevas o de como se han implementado las que ya conocíamos de EF 6.X.  Por suerte, cada vez tenemos más características que enseñar o más capacidades dentro de las características ya existentes que hacen que estas charlas no sean tan repetitivas.

Una de estas características nuevas que suele llamar la atención es el concepto de Shadow Properties, o propiedades que existirán en nuestro modelo relacional pero no las tendremos «visibles» en nuestro modelo de entidades. Para explicar estas propiedades, casi siempre suelo recurrir al típico ejemplo de propiedades de «fontanería» como por ejemplo los típicos conceptos de UpdatedBy, UpdatedOn. Por lo general este tipo de elementos los queremos como elementos básicos de funcionamiento pero no son importantes a la hora de modelar un problema, por eso nos referimos a ellos como elementos de «fontanería». Incluir estos conceptos resulta de lo más trivial como podemos ver a continuación:

Fíjese como en nuestro método de configuración del modelo, OnModelCreating, hemos dispuesto dos propiedades nuevas que no tenemos en nuestra entidad. Si hacemos una simple migración podríamos ver como efectivamente EF generará estos elementos en nuestro modelo relacional.

Por supuesto, y más en este caso que las hemos establecido como requeridas, tenemos que tener la posibilidad de establecer los valores de las mismas. Aunque hay diferentes alternativas y patrones de código para hacer esto relativamente sencillo lo más natural para demostrarlo sería recurrir a nuestro SaveChanges para hacer este trabajo.

Pues bien, aunque las Shadow Properties, se explican muy bien con estos conceptos de fontanería en realidad pueden tener más utilidades. Si hay algo que mucha gente pregunta con respecto a EF 6.X es  que ya no existe el concepto de ComplexTypes, que por lo general eran usados como ValueObjects en estilos orientados al dominio. Una forma simple para realizar ValueObjects dentro de EF Core podría ser precisamente con el uso de Shadow Properties. Para ello, veamos un ejemplo simple, que por supuesto tiene detalles que deberían ser revisados y/o mejorados.

Lo primero, será definir una pequeña clase base que nos permita marcar ciertos elementos como Value Objects y por lo tanto que sepa compararlos por su contenido. Para ello, podemos buscar por internet muchos ejemplos de implementaciones, aunque lo más básico ( no lo mejor ) podría ser algo como esto:

 

Una vez definida esta clase, podemos ya marcar nuestras entidades con la misma, por ejemplo una clase Address, que podríamos escribir como sigue:

¿Donde entre el uso de las Shadow Properties? Pues bien, una de las cosas que restringimos en nuestros Value Objects es el concepto de identidad en contenido. Es decir dos direcciones son iguales si su contenido es el mismo no si una clave de identidad es igual. Sin embargo EF nos obliga a que todas las entidades que mapeemos tengan un clave primaria/identidad. Las Shadow Properties nos permitirán sacar esta «restricción» fuera de nuestra clase Address y sin embargo que EF siga pudiendo funcionar.

En este caso el mapeo podría realizarse como sigue:

Como hemos visto, el concepto de Shadow Properties nos habilitan más escenarios que el simple de mecanismos de fontanería. En este caso hemos visto otro uso con respecto a la definición de Value Objects pero seguro que se le ocurren muchos más.

 

Saludos

Unai