lunes, 12 de diciembre de 2011

Entity Framework, DefiningQuery ¿Virtud o defecto?

En anteriores post vimos los distintos tipos de asociaciones disponibles, así como distintas soluciones para implementar la herencia.

Ahora nos toca ver como trabajar con vistas en nuestro modelo EDM.

Para llevar a cabo los ejemplos de este post, partimos de una base de datos una vista llamada DireccionesPorCliente (una simple INNER JOIN entre tablas Cliente y Direcciones)

Al crear nuestro modelo con Database First (esto es primero la base de datos y después generar el modelo con el asistente) podemos observar que se ha creado una entidad llamada “DireccionesPorCliente” donde todos sus campos son clave. Esto es así porque cualquier entidad en EF tiene que tener al menos un campo clave y, al no encontrar EF ningún campo candidato, toma la determinación de que todos los campos serán clave. Lógicamente somos libres de modificar la entidad para que sólo un campo o varios sean clave. En realidad y puesto que la entidad resultante de la vista será de sólo-lectura, es simplemente una cuestión de rendimiento y/o comodidad el dejar que todos los campos sean clave.

Por otro lado, la sección SSDL (la sección de nuestro fichero edmx que define la estructura de la base de datos) ha incluido un elemento DefiningQuery que incluye un comando SQL nativo para obtener los datos de la vista. Esto significa que las vistas que se basan en DefiningQuery no podrán ser migradas automáticamente si cambiamos el gestor de base de datos de nuestro modelo, puesto que están atadas a un gestor concreto y su lenguaje SQL específico.

<EntitySet Name="DireccionesPorCliente" EntityType="EFModel.Store.DireccionesPorCliente" store:Type="Views" store:Schema="dbo" store:Name="DireccionesPorCliente">   
<DefiningQuery>
SELECT       
[DireccionesPorCliente].[IdCliente] AS [IdCliente],       
[DireccionesPorCliente].[Nombre] AS [Nombre],       
[DireccionesPorCliente].[IdDireccion] AS [IdDireccion],       
[DireccionesPorCliente].[Direccion] AS [Direccion],       
[DireccionesPorCliente].[Poblacion] AS [Poblacion],       
[DireccionesPorCliente].[CP] AS [CP]      
FROM [dbo].[DireccionesPorCliente] AS [DireccionesPorCliente]
</DefiningQuery>
</EntitySet>

Lo cierto es que según como se mire, no todo son desventajas con los elementos DefiningQuery.


Por ejemplo, el mayor defecto de DefiningQuery también podría ser su mayor virtud. Podríamos beneficiarnos de que guarda el comando SQL en el lenguaje nativo de la base de datos para construir nuestras propias DefiningQuery sin la necesidad de que exista una vista en la base de datos subyacente, y además todo ello con la flexibilidad de poder ejecutar cualquier código SQL que sea válido para el gestor de base de datos (imagino que no quieres dar al traste con todos tus años de experiencia y conocimiento en el lenguaje SQL de tu gestor de base de datos favorito, ¿no?)


En cualquier caso, lo que sí está claro es que el elemento DefiningQuery supondrá series dificultades si queremos migrar nuestro modelo EDM a un gestor de base de datos distinto del actual, pero si no es el caso, bienvenidas sean y podrían ayudarnos a resolver ciertos escenarios.


Imagina ahora que tienes una super-SQL que recupera cierta información de la que quieres disponer en tu modelo a través de una entidad. Asumiendo que no sabemos o no queremos utilizar eSQL, LINQ o un procedimiento almacenado, parece que sólo nos queda la vía del elemento DefiningQuery.


Para crear nuestros propios elementos DefiningQuery necesario editar manualmente el fichero .edmx. Si quieres conocer los pasos necesarios visita el siguiente enlace de MSDN.


A grandes rasgos, lo que se hace es agregar el XML necesario en las secciones SSDL, CSDL y MSL en nuestro fichero edmx. De hecho, el XML agregado es exactamente igual al que podría haber generado el asistente de EF si importamos una vista con la excepción del elemento EntitySet de la sección SSDL.


El elemento DefiningQuery que importamos desde la base de datos (luego está ligado a una vista en la base de datos subyacente) es:


<EntitySet Name="DireccionesPorCliente" EntityType="EFModel.Store.DireccionesPorCliente" store:Type="Views" store:Schema="dbo" store:Name="DireccionesPorCliente">


Por otro lado, nuestra vista personalizada sin ningún tipo de atadura con una vista en la base de datos subyacente es igual pero sin las propiedades store.Type, store:Schema y store:Name. Es decir, todas las propiedades que ligan el elemento de nuestro modelo a un elemento de base de datos se han eliminado.


<EntitySet Name="DireccionesPorCliente" EntityType="EFModel.Store.DireccionesPorCliente">


Qué conste que yo no recomiendo usar DefiningQuery porque está claro que rompe con el patrón de ignorancia de la persistencia, pero al menos hay saber que posibilidades tenemos con este elemento y después cada uno que haga lo que crea oportuno.


Además, en el momento en que actualices el modelo, las secciones personalizadas SSDL y MSL será eliminadas por lo que vuelta a empezar.


Por último, casi todo lo expuesto en este post es igualmente aplicable al elemento QueryView.


Una QueryView es una vista sobre el modelo conceptual, es decir, no se basa en una vista de la base de datos subyacente, sino que a través de eSQL expresa una consulta sobre las entidades de nuestro modelo.


Igualmente un QueryView no tiene soporte en el diseñador y hay que editar manualmente el fichero edmx.


Cabe mencionar que tanto con DefiningQuery como con QueryView, las entidades resultantes son de sólo lectura.


Un saludo!

No hay comentarios:

Publicar un comentario