LINQ to Entities y Visual Basic 2008 – n-capas – Parte 4
Introducción
En el anterior artículo, veíamos como iniciarnos en la filosofía de n-capas utilizando Microsoft ADO.NET Entity Framework.
Aún nos falta mucho recorrido y este tema nos daría para algunas entradas o artículos más, pero vamos a ir desgranando poco a poco las bondades, problemas, dudas y preguntas que nos pueden surgir a la hora de iniciarnos con LINQ to Entities y las aplicaciones de n-capas.
En el anterior artículo, nos quedamos revisando lo que tiene por «fuera» ADO.NET Entity Framework, pero aún no sabemos lo que tiene por «dentro». Eso es lo que veremos a continuación.
Lo que tiene por “dentro” un elemento ADO.NET Entity Data Model
Ahora bien, vamos a volver al proyecto y ver más detalles relacionados con el EF. Resumiendo nos encontramos con que:
Tenemos como hemos dicho al principio, un proyecto de tipo WinForm.
Dentro del proyecto hemos agregado un modelo de datos EF.
En el asistente creamos una cadena de conexión con el modelo físico que se almacenó en el archivo de configuración de aplicación App.Config.
El aspecto del archivo de configuración de aplicación App.Config es de la siguiente forma:
<?xml version=«1.0« encoding=«utf-8«?> <configuration> … <connectionStrings> <add name=«FUTBOL2006Entities« connectionString=«metadata=.Futbol2006.csdl|.Futbol2006.ssdl|.Futbol2006.msl; provider=System.Data.SqlClient;provider connection string="Data Source=CLUNIA;Initial Catalog=FUTBOL2006; Integrated Security=True;MultipleActiveResultSets=True"« providerName=«System.Data.EntityClient« /> </connectionStrings> </configuration> |
Como podemos observar, aquí se nos indica una cadena de conexión y un nombre de proveedor (System.Data.EntityClient).
Respecto a la cadena de conexión observamos que se indican tres ficheros de metadatos (csdl, msl y ssdl) como pudimos ver en el asistente.
La pregunta por lo tanto es… ¿pero dónde están estos metadatos?. ¿Los genera el entorno en tiempo de ejecución?. Si lo hace en tiempo de ejecución, ¿dónde los almacena realmente?. ¿Cómo funcionaría una aplicación típica cliente-servidor?.
Evidentemente, esos tres archivos de metadatos existen ya en el sistema. La pregunta entonces sería saber dónde se encuentran. La respuesta es en el directorio bin/Debug como se indica en la siguiente captura de pantalla.
¿Y qué contiene esos tres archivos?. Contenido XML del modelo. Así de simple.
No vamos a entrar ahora en el detalle más profundo, pero establecen todas las partes de nuestro modelo.
Pero hay algo más que aún no he explicado y que lo haré a continuación.
Todo son clases
Otro aspecto que debemos tener en cuenta es como organiza Microsoft el modelo de entidades.
Para ello, primero acudiremos al visor de clases y observaremos que en nuestro proyecto tenemos un namespace denominado Futbol2006Model (¿os suena que ya hemos utilizado ese nombre en la ejecución del asistente?).
El caso es que analizando ese nombre de espacio, vemos el conjunto de clases creadas de acuerdo al modelo de entidades.
Una vez más, debemos preguntarnos en qué lugar se almacena entonces la información de las clases creadas de acuerdo al modelo de entidades.
En este caso, debemos acudir al fichero de extensión edmx. Se trata de un documento XML con información directa del modelo de entidades, y que enlaza con un fichero (Futbol2006.Designer.vb) que contiene clases parciales escritas en VB y que definen la entidad, sus propiedades, métodos, etc.
Ahora bien, igual estás pensando en qué ocurre si queremos extender las clases del modelo de entidades. ¿Es posible llevarlo a cabo?. La respuesta es sí, pero para poder llevarlo a cabo, deberemos crear otro archivo aparte del Futbol2006.Designer.vb, ya que si incluimos nuestra personalización dentro de ese archivo, al actualizar, refrescar y/o ejecutar nuestra aplicación de acuerdo al modelo, realizará una validación que eliminará el código sobrante, y el código sobrante que no hace falta utilizar al modelo es la personalización que hayamos realizado dentro del archivo Futbol2006.Designer.vb, de ahí que la personalización si la hacemos, debamos hacerlo fuera de ese archivo.
Distribuyendo nuestra aplicación
Aunque nada de lo que hemos visto hasta ahora es despreciable, digamos que ahora viene lo mejor de todo ya que vamos a empezar a discutir la idoneidad de algunas cosas que podríamos hacer o no, y hacernos preguntas interesantes.
En primer lugar pensemos en nuestra aplicación de WinForms como un todo, tal y como lo hemos hecho hasta ahora.
Nuestra aplicación contendrá un modelo de entidades y el ejecutable. Todo en uno.
En este ejemplo, hemos agregado un control Button y un control DataGridView.
El código que hemos agregado es el siguiente:
Imports EntityCapas.FUTBOL2006Model Public Class MainForm Private Sub btnExecute_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecute.Click Dim contexto As New FUTBOL2006Entities Dim players = From p In contexto.Futbolista Where p.Club.Codigo = «RMA» Select p Me.dgvData.DataSource = players Me.dgvData.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells) End Sub End Class |
En el caso de distribuir nuestra aplicación, tendremos un ejecutable que corresponderá con nuestra aplicación Windows.
Crearemos para esta prueba, un directorio Windows vacío e insertaremos en este directorio el fichero ejecutable de nuestra aplicación, para acto seguido, ejecutar la aplicación.
Al pulsar sobre el botón, se generará un error. Evidentemente, nos hemos olvidado de llevarnos el archivo App.Config al directorio dónde está el ejecutable. ¿Os acordáis que ese archivo tenía la cadena de conexión con el modelo físico?.
Bien, nos llevamos entonces el fichero App.Config allí y ejecutamos nuevamente la aplicación y pulsamos el botón.
Ahora aparece un mensaje que nos indica que faltan los ficheros que se indican en la cadena de conexión del App.Config y que corresponde con los archivos csdl, ssdl y msl.
Nos vamos a nuestro proyecto, y copiamos esos archivos en el directorio dónde estamos poniendo nuestra aplicación de demo.
Ejecutamos nuevamente nuestra aplicación, pulsamos el botón, y ahora sí, vemos como los datos son recogidos correctamente en la aplicación sin ningún tipo de error.
De todo este proceso, sacamos varias conclusiones:
- Al distribuir nuestra aplicación, debemos indicarle la cadena de conexión al modelo físico y a los ficheros metadatos.
- Por defecto, la cadena de conexión se crea en el archivo App.Config, por lo que distribuir este archivo, puede accarearnos problemas de seguridad. Una posible solución sería encriptar la cadena de conexión, pero seguimos teniendo altos riesgos de intrusión al poder utilizar herramientas que permitan romper la cadena de conexión.
- Adicionalmente, debemos también distribuir los archivos de metadatos, lo cual hace más pesada la distribución de nuestra aplicación.
Así que con todo esto, nos vemos delante de una interesante encrucijada. ¿Cómo debemos actuar?. Por supuesto que depende del escenario, pero lo ideal es que los clientes tengan el menor acceso posible a información sensible, y una cadena de conexión o los metadatos lo es.
Girando la tuerca por primera vez y buscando una mejor opción
En primer lugar, estudiaremos la posibilidad de reducir los archivos de distribución a la hora de trabajar con EF o mejorar la forma de distribuir nuestra aplicación utilizando el modelo de EF.
De primeras, hemos visto que para distribuir la aplicación, debemos distribuir:
- El fichero ejecutable.
- El fichero de configuración.
- Los tres archivos correspondientes a los metadatos.
Este tipo de distribución no es bajo mi punto de vista el tipo de distribución ideal, pero a priori es la forma más básica de hacerlo.
Pensemos ahora entonces, en intentar mejorar este tipo de distribución, modulando la aplicación de alguna manera. Para ello, crearemos en primer lugar una solución con dos proyectos.
El primer proyecto será el del proyecto WinForm que hemos hecho hasta ahora.
El segundo proyecto será una biblioteca de clases dentro de la cuál agregaremos el modelo de EF.
Luego desde el primer proyecto WinForm, consumiremos la biblioteca de clases. De todos los modos, pensando así de sopetón, deduciremos que el ensamblado de la biblioteca de clases debería tener también los “famosos” archivos de metadatos… ¿o quizás no?. Eso es lo que veremos a continuación.
Agregaremos a la solución por lo tanto, un nuevo proyecto de biblioteca de clases. Aparecerá por defecto una clase que eliminaremos porque no la vamos a usar para nada, así que la idea es tener el esqueleto de un proyecto.
Dentro de ese esqueleto agregaremos un nuevo elemento de tipo ADO.NET Entity Data Model, y a continuación realizaremos con ayuda del asistente las mismas acciones que vimos anteriormente para preparar el nuevo modelo de datos.
Una vez superado este paso, agregaremos a nuestro proyecto WinForm una referencia al ensamblado de la biblioteca de clases que contiene el modelo y escribiremos el código de nuestra pequeña aplicación.
El código quedará de la siguiente manera (se aprecia que solo se modificaría con respecto al anterior código la importación del correspondiente namespace):
Imports EntityClasses.FUTBOL2006Model Public Class MainForm Private Sub btnExecute_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecute.Click Dim contexto As New FUTBOL2006Entities Dim players = From p In contexto.Futbolista Where p.Club.Codigo = «RMA» Select p Me.dgvData.DataSource = players Me.dgvData.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells) End Sub End Class |
Ahora llega el turno de crear el ejecutable y distribuir nuestra aplicación. En este punto tendremos las siguientes partes separadas que juntas conforman la distribución de la aplicación:
- El fichero ejecutable.
- El fichero de configuración.
- Los tres archivos correspondientes a los metadatos.
- El ensamblado de la biblioteca de clases.
Analizando el resultado, veremos que el hecho de haber apartado el modelo de datos a una biblioteca de clases ha hecho que generemos un fichero más en su distribución, el correspondiente al ensamblado del modelo de datos.
Siempre podremos, no obstante, utilizar alguna herramienta para unir ensamblados o algo similar, pero aún y así, lo ideal sería poder reducir el número de ficheros a distribuir de forma que el proceso de implantación fuera más sencillo y a ser posible, más modular. Cuantos más ficheros a distribuir, más riesgos de que haya algo que se nos pueda estar olvidando, y cuanto menos modular más encorsetado. El equilibrio entre ambos es difícil, pero al mismo tiempo necesario.
En el siguiente artículo, veremos como podemos acercarnos un poco más hacia el comienzo de lo que son las n-capas con EF.
3 Responsesso far
Jorge como estas?Justamente estoy entrando en el tema de EF y modelo de capas, y cuando desesperaba de encontrar algo, me encuentro con tu blog! Muy buenos los articulos, y quedo a la espera del siguiente… yo te paso si queres mi inquietud. Pasa que si uno quiere hacer un modelo de capas, las entidades de negocio (que serian las entidades EF) deben ser accesibles desde todas las capas (Entidades, Reglas,UI). Para poder acceder desde UI (en un modelo de capas similar al que vos propones) tenes que importar la libreria de Entities… lo que conlleva traerse toda la «logica pesada» del EF. La pregunta sería cómo hacer para mantener esa lógica pesada «abajo».
Un saludo y me mantengo al tanto.
-Estoy investigando y una ventaja que veo con Entity Framework es que tipa las consultas, pero como suelo usar stored procedures, no gano nada. No acostumbro a consultas a nivel de aplicación.
-Por otro lado, en una primera impresión parece un sistema común para atacar a distintas base de datos pero solo veo que funciona para SQL así que tampoco veo ventaja aquí.
-TableAdapters a pesar de ofrecer demasiada visibilidad de objetos en el modelo de n-capas, hecho que me enfurecía, no dejaba de ser un beneficio para el desarrollador y no se dudaba de su uso. ¿Acaso Entity Framework muestra menos objetos a las capas subyacentes que consumen de la Data Access Layer? A mi me parece mas maquinaría pesada como ocurría con TableAdapters.
-Y yo me pregunto ¿que mejora Entity Framework mas LINQ en un modelo n-layer? ¿qué motivos tengo para implementarlos en mis nuevos proyectos? Yo no lo veo claro sin embargo a la gente les encanta las novedades.
He estado realizando pruebas con ejemplos que utilizan EDM y comparando los tiempos de ejecución con un proceso en el que utilizaba un SqlDataAdapter y un DataSet, en todos los casos para rellenar un ListBox, utilizando las propiedades DataSource y DisplayMember del control y los resultados son los siguientes:
– Con los metodos que utilizan EDM : 720ms
– Utilizando SqlDataAdapter: 125 ms.
José Miguel Galache López
josemiguel@galache.eu