4.19.2009

El Entity Framework en una Arquitectura n-Layer – Parte 1

En el post anterior acerca del Entity Framework en una arquitectura n-layer, describí el rol que juega el EF en una arquitectura n-layer. En este post vamos a crear un ejemplo para mostrar como se plasma en código las ideas expuestas en el post anterior.

En este caso, vamos a trabajar en el desarrollo de una “mini” aplicación que administra los casos de uso de n empresas – al menos desarrollar un poquito de funcionalidad de la aplicación para ilustrar los conceptos expuestos.

La Base de Datos

El primer paso es crear una base de datos para persistir la información de los proyectos. Vamos a crear una base de datos utilizando SQLServer2008. Esta base de datos se llamará UseCases. El diagrama inicial de la base de datos es el siguiente.

image

En este caso, vamos a decir que una empresa puede tener varios proyectos, y que cada proyecto tiene muchos casos de uso. Cada caso de uso tiene un historial de acciones que se graba cada vez que se realiza un cambio en el caso de uso ( esto suponiendo una base de datos completa, en donde se guardan los diferentes flujos del caso de uso, sus actores, etc). Por último, cada registro del historial de cambios tiene un usuario asociado que es precisamente el que realizó el cambio.

Desarrollando la Solución

Para el desarrollo de la solución vamos a utilizar Visual Studio 2008 SP1. El primer paso es crear una solución vacía para ir agregando los diversos proyectos que vamos a ir requiriendo en el desarollo de la aplicación. Para crear una solución vacía seleccionamos: new project –> visual studio solutions –> Blank Solution.

image

Creando la capa de Acceso a Datos

Una vez que tenemos la solución, vamos a crear la capa de acceso a datos ( que por lo general es el primer bloque que se crea cuando se realiza un proyecto con arquitectura n-layer). Para agregar el proyecto, seleccionamos con el botón derecho del mouse la solución recién creada y seleccionamos del menú contextual agregar nuevo proyecto.

imageCuando aparece la opción de seleccionar el tipo de proyecto deseado seleccionamos la opción de class library en el tipo de proyecto Windows bajo C#. Al proyecto le vamos a poner de nombre CapaDeAccesoADatos.

image Después de creada la capa de acceso a datos – al menos el proyecto – procedemos a agregar el modelo del entitiy framework. Debemos recordar, que en el post anterior mencioado al principio de este post, indicabamos que el EF sustituye a la capa de acceso a datos. Por esta razón en este componente de acceso a datos, solamente vamos a tener el modelo generado por el EF; en post posteriores vamos a extender el EF con clases adicionales que se agregarán a esta librería.

Para crear un modelo de entitidades le damos clic y botón derecho al proyecto recién creado y seleccionamos agregar nuevo ítem.

image En el diálogo de seleccionar ítem escojemos la opción ADO.NET Entity Model. Le vamos a llamar UseCasesModel.

image Cuando inicia el “wizard” del EF en el primer paso seleccionamos la opción generar desde base de datos. Seguidamente creamos una nueva conexión a la base de datos que recién acabamos de crear; le decimos además al wizard que agregue el string de conexión al archivo app.config con el nombre UseCasesEntities.

image Seleccionamos Next y procedemos a seleccionar las tablas que vamos a utilizar en nuestro modelo. En este caso, vamos a mapear en el modelo, todas las tablas creadas en el diseño de la base de datos hecha en SQLServer.

image El modelo generado es el siguiente

image Podríamos caer en la tentanción de pensar que lo único que el EF hace es mapear las tablas en clases y ponerlas a nuestra disposición para las tareas tradicionales que llevamos normalmente a cabo en una base de datos tales como el CRUD. Pero si vemos el modelo generado con atención, podemos ver que han sucedido cosas interesantes gracias a la forma en que ser tratan las relaciones entre objetos y entre tablas. Tal vez el cambio que esta más a la vista, es que los campos que manejan las llaves foráneas en la base de datos, fueron sustituidas por objetos de navegación. Esto nos permite una mayor flexibilidad ya que podemos navegar en ambas direcciones en la tabla, y el EF se encarga de administrar las relaciones a nivel de tablas.

En el paso que estamos, la solución debería lucir de la siguiente manera:

image En este momento solo tenemos una librería – dll – que va a convertirse en mi capa de acceso a datos. En el próximo post, vamos a desarrollar la capa de lógica de negocios.

Technorati Tags: ,

16 comentarios:

Ale Afonso dijo...

Luis, quisiera saber cuál es la ventaja de crear una solución con varios proyectos con respecto a crear un solo proyecto con distintas carpetas? Lo que se me hace más evidente es la reusabilidad del código aunque esto también lo pudieras lograr extrayendo las carpetas de manera manual de un proyecto a otro.

Esta duda se me generó debido a que, siguiendo tus lineamientos, llegué al punto de querer agregar como referencia el proyecto de Lógica de Negocios al de Acceso a Datos y me produjo el error de dependencia circular (porque ya había agregado la referencia del DAL al BLL).

¿Para qué querría hacer eso? Para agregar métodos en la Capa de Acceso a Datos que me den mayor flexibilidad que el EF para lo cual requiero conocer la estructura del objeto que se encuentra en la Lógica de Negocio y así poder comunicar ambas capas mediante dicho objeto.

De antemano, agradezco cualquier ayuda que me puedas brindar.

Saludos,

Luis D. Rojas dijo...

Uno normalmente pone varios proyectos por solución por una cuestión de orden. Además, uno configura la solución para que construya todos los binarios en un solo directorio ( yo siempre utilizo BINN en la raíz de la solución ) y así poder crear el instalador del objeto. Igualmente con este método no tengo problemas de versionamiento con los componentes que creo y que hago referencia desde mi proyecto.
Respecto a la referencia circular, no se debe crear una referencia desde la capa de acceso a dato a la capa de negocios, esto simplemente por que no es necesario. La capa de acceso a datos solo interactúa con el repositorio de datos y el medio de transporte que utiliza para comunicarse con la lógica de negocios son las entidades de negocio. Las entidades de negocio son el estado de las clases de la lógica de negocio, la cual representa el comportamiento. El entity Framework juega el rol de entidad de negocio por que genera las clases que me representan el estado de mi lógica de negocios, pero además, maneja la interacción con el repositorio de datos, por lo que también me abstrae la funcionalidad de la capa de acceso a datos.

Sebastián dijo...

Lo has intentado con otros motores que no sean SQLServer, por ejemplo MySQL?

Si EF pretende reemplazar al uso de los providers y todo lo que hacíamos en la capa de datos estaría bueno que soporte cualquier motor o por lo menos los mas usados.

Excelente post.
Saludos
ElSebas.net

Juanma dijo...

Buenas, tengo una duda (ojalá fuera una, jeje), con el archivo app.config en el cual viene la cadena de conexión de la aplicación de escritorio ya no hace falta crear la conexión a la BD en una clase aparte ni tampoco abrir y cerrar conexiones cada vez que se hacen operaciones contra la bd????o simplemente al instalar la aplicación e iniciarla ya se conecta automáticamente a la bd desde el principio y no se cierra la conexión hasta que no cerramos la aplicación??.
Muchas gracias, de tooodos los post que he buscado sobre diseño de aplicaciones en 3-capas este es el que más me ha ayudado.

Luis D. Rojas dijo...

Hola Juanma, gracias por leer el blog y comentar.
Mira, es correcto lo que indicas, ya el EF se encarga de manejar las conexiones a la base de datos.. en realidad ese es el objetivo del ORM, abstraer el repositorio y todas sus funciones del tema del negocio

Guillermo dijo...

Te felicito por tu blog. Estoy empezando en el uso del Entity Framework, me parece excelente la explicación. Gracias.

Luis D. Rojas dijo...

Gracias Guillermo por leer el blog y por tus comentarios.

Hugo dijo...

Buenas Diego, desde hoy estaré revisando tu blog para complementar lo que nos estás enseñando. Al principio me parecia todo escrito en chino pero ya ciertos conceptos son comprensibles. Saludos.

Luis D. Rojas dijo...

Gracias Hugo por tus comentarios y espero sigas leyendo el blog :)

Nelson Yessy dijo...

Excelente tus aportes y tu blog, esta muy bacano.... desde Colombia, saludos

Luis D. Rojas dijo...

Gracias Nelson por tus comentarios y por tomarte el tiempo de leer el blog.

Saludos

Luis Angel dijo...

Luis, megustaria saber si no te ha causado conflicto hacer un instalador.
gracias.

Luis D. Rojas dijo...

Hola Luis Angel,
gracias por leer el blog.
La verdad no, solo hay que tener en cuenta el cambio en el servidor del string de conexión para el caso donde la base de datos esta en otro servidor o máquina

saludos

Luis Angel dijo...

Hola soy nuevo en esto y estoy haciendo un trabajo para la escuela pero tal parece que no he podido hacer mi instalador como lo hacia antes con un tableAdapter. mi base de datos la tengo con mysql y no he podido hacer el instalador, he logrado instalarlo en una maquina pero tiene instalado el .net 2010 y si no me marca un error


Firma con problemas:
Nombre del evento de problema: CLR20r3
Firma del problema 01: wfcontroltiempos.exe
Firma del problema 02: 1.0.0.0
Firma del problema 03: 4e025895
Firma del problema 04: System.Data.Entity
Firma del problema 05: 3.5.0.0
Firma del problema 06: 4a17460e
Firma del problema 07: 1b48
Firma del problema 08: a
Firma del problema 09: System.ArgumentException
Versión del sistema operativo: 6.1.7600.2.0.0.256.1
Id. de configuración regional: 2058

Luis Angel dijo...

agradesco mucho tu ayuda.

saludos.

Unknown dijo...

HOla que tal .. estoy siguiendo tus ejemplos pero tengo una dificultad. Estoy trabajando con el entity framework y tengo 2 tablas en la base de datos. Una de productos y una de estados. Existe la relación entre las tablas por su estado (ESTADO_ID). Pero cuando voy a a agregar el campo relacionado no lo encuentro. Este es el código de la interface de usuario:

TABLA_PRODUCTO objProducto = new TABLA_PRODUCTO ();
ProductoBL objLogicaNegocio = new ProductoBL();

objProducto.PRODUCTO_NOMBRE = this.txtNombreProducto.Text.ToUpper();
objProducto.PRODUCTO_DESCRIPCION = this.txtDescripcionProducto.Text.ToUpper();
objProducto.PRODUCTO_PRECIO = Convert.ToDecimal(txtPrecioProducto.Text);
objProducto.PRODUCTO_INVENTARIO = Convert.ToInt32(txtCantidadProducto.Text);

objLogicaNegocio .AddProduct(objProducto);

No deberia existir un ESTADO_ID para poder asignarlo asi:

objProducto.ESTADO_ID = 1;

Y otr4a pregunta. Si quiero utilizar WebServices, esto irian entre la capa de Negocios y la capa de Datos? O como funciona esto

Gracias