5.04.2009

El Entity Framework en una Arquitectura n-layer – Parte 3

En los posts anteriores creamos la capa para la lógica de negocios y la capa de acceso a datos utilizando el entity framework. En este post, vamos a crear la capa de presentación de la aplicación de ejemplo utilizando WPF.

El primer paso es crear un nuevo proyecto dentro de la solución en la cual hemos venido trabajando. El proyecto a crear es una aplicación WPF.

image

Seguidamente, eliminamos la forma que se crea por defecto, y creamos una nueva pantalla. En este caso, vamos a crear una pantalla para agregar un usuario. Como podemos ver en el primer post, un usuario tiene básicamente los siguiente campos:

  • Id
  • Nombre
  • Apellido1
  • Apellido2
  • Email
  • Activo.

De estos campos, el Id es autogenerado y el campo de activo es para borrado lógico por lo que en la inserción por defecto, el campo se guarda con un valor de “Y”.

La pantalla que vamos a crear por lo tanto deberá lucir como se ve en la siguiente figura:

image Seguidamente vamos a agregar el código necesario para agregar la entidad ingresada en la forma, pero antes de esto, debemos agregar una referencia a la capa de lógica de negocios y a la capa de acceso a datos. A esta última la tenemos que agregar por que las entidades son el “medio de transporte” entre las capas, y como no tenemos una capa de entidades separada, entonces tenemos que agregarla desde la capa de acceso a datos. Además se debe de agregar una referencia a la librería System.Data.Entity. El código lucirá de la siguiente forma:

using System.Windows;
using CapaDeAccesoADatos;
using LogicaDeNegocios;

namespace Cliente_WPF
{
public partial class DetalleUsuario
{
public DetalleUsuario( )
{
InitializeComponent( );
}
private void btnOk_Click( object sender, RoutedEventArgs e )
{
Usuario usuario = new Usuario( );
usuario.Nombre = txtNombre.Text;
usuario.Apellido1 = txtApellido1.Text;
usuario.Apellido2 = txtApellido2.Text;
usuario.Email = txtEmail.Text;
usuario.Activo = "Y";
UsuarioBL usuarioBL = new UsuarioBL( );
usuarioBL.AgregarUsuario(usuario);

}
}
}



Como podemos ver, lo único que hacemos es crear una entidad, crear una instancia de la clase usuario de la lógica de negocios e invocar el método agregar usuario pasando de parámetro la entidad del usuario recién creada. Este código, además de simple, es sencillo de mantener y permite que todos los desarrolladores que estén trabajando en el proyecto, tengan un estilo similar para programar, lo que facilita el hecho de que una persona no este disponible para modificar o agregar funcionalidad a una pantalla.



Si ejecutamos la pantalla anterior, veremos la siguiente pantalla en ejecución:



image



Si ingresamos datos, y le damos ok, vamos a recibir el siguiente error de parte del entity framework:




The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.




Esto quiere decir que el entity framework no esta encontrando el conection string para pegarse a la base de datos. Este connection string se encuentra en el archivo app.config de la librería de acceso a datos; pero en este caso, como no tenemos configurada la salida de todos los proyectos al mismo directorio – algo de lo que vamos a ir conversando en post posteriores – entonces la aplicación no lo logra localizar. Para solucionar este problema de forma rápida – y temporal -  debemos simplemente agregar un archivo app.config al proyecto del cliente WPF y copiar el connection string desde el app.config de la capa de acceso a datos.



El primer paso es agregar el archivo config al cliente de WPF.



image



Seguidamente copiamos desde el archivo app.config de la capa de acceso a datos, el string de conexión al archivo recién creado



<connectionStrings>
<
add name="UseCasesEntities" connectionString="metadata=res://*/UseCasesModel.csdl|res://*/UseCasesModel.ssdl|res://*/UseCasesModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=diego-pc\sqlserver2008;Initial Catalog=UseCases;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</
connectionStrings>


Seguidamente, procedemos a ejecutar la aplicación y a insertar los usuarios que vayamos a necesitar.



En el siguiente post, vamos a crear una pantalla para que se nos muestre a través de el DataGrid del toolkit de WPF, todos los usuarios ingresado en la base de datos.



Technorati Tags: ,,,

43 comentarios:

José dijo...

Me parece que hay un error en esta capa porque apunta a la capa de acceso a datos para crear una instancia de la entidad, viola el principio de la separaciòn en capas.

Diego Rojas dijo...

Gracias por el comentario Jose.
Mirá, no es así por que en este caso, las entidades del negocio, con son una capa que normalmente se hacia de forma separa, ahora residen en el esquema del entity framework, osea en la capa de acceso a datos, por lo tanto necesitas una referencia al DACL para tener visibilidad de las entidades.
Si tuvieras una capa de entidades - POCOS como se le llama en .NET - tendrias que hacer referencia a tu entity layer, pero en este caso esta abstraído por el entity framework. Es decir, el EF abstrae la comunicacion con el repositorio, y la capa de entidades del negocio.

Saludos

Miguel dijo...

Como comenta José, creo que se esta violando el principio de separación de capas.

También es cierto lo que responde Diego, necesitamos esas entidades definidas en la capa de Acceso a datos.

¿Será entonces que no podemos utilizar entity framework sin violar el principio de separación de capas?

Diego Rojas dijo...

Gracias Miguel por tu comentario. En realidad cuando uno hace una aplicación n capas sin el EF, uno debe de crear una capa de entidades que sirven como medio de transporte entre las capas, estas capas normalmente son POCOS, y son clases serializables para que puedan ser consumidas por servicios - no solo por servicios web. En este caso, lo que el EF hace es abstraer la capa de acceso a datos y esta capa de entidades, entonces como necesitamos un medio de transporte entre capas, necesitamos tener una referencia al DACL por que ahi es precisamente donde están las entidades. Este es un concepto de separación que se aplica sin el EF, ya que uno debe dividir el estado del comportamiento y el estado es lo que se representa en la capa de entidades.

Saludos

Miguel dijo...

Este tema de EF es apacionante :-).
Desde que empece a desarrollar aplicaciones n-layer mis maestros me explicaron que estaba prohibido desde el assembly de la capa de presentación agregar una referencia al assembly de la capa de acceso a datos, esto es, solo debo agregar referencia a la capa de lógica y a la capa común (POCOS) donde están mis entidades. Así que según el principio de separación de capas, no puedo utilizar en la capa de presentación los tipos definidos en la capa de acceso a datos.

¿Qué opinas?

Espero haber explicado mis inquietudes.

Diego Rojas dijo...

Que tal Miguel? De verdad que sí, el EF viene a cambiar un poco la forma en que desarrollamos aplicaciones n-layer ( e incluso n-tier ). En este punto como te dije anteriormente, no es que agregar una referencia desde el UI o desde la capa de servicios al DACL sea un pecado mortal -Incluso en muchas aplicaciones se utiliza el MVC como patrón y desde el controller se accede a la capa de acceso a datos - aunque en realidad se debería acceder la lógica de negocios. El principio de separación no sirve para separar los conceptos de cada capa, es decir, el DACL me abstrae el tipo de repositorio y la capa de UI me abstrae como voy a presentar mis datos. En este caso el EF cumple con este concepto, aunque en realidad, el único problema que le encuentro es que podemos acceder a lógica del DACL a directamente desde el UI - algo que si comprometería el concepto de separación de capas. Te dejo un link a una imagen en un sitio de Microsoft donde se muestra una arquitectura utilizando el EF - como puedes ver, las entidades son verticales y van desde el dacl hasta el ui.
The Entity Framework In Layered Architectures

Saludos y gracias por escribir

Miguel dijo...

Efectivamente, parece ser que no hay otra opción más que agregar una referencia de la capa de acceso a datos. Solo debemos tener cuidado de utilizar únicamente las entity types.

Muchas gracias y seguimos en contacto :-)

Alan dijo...

Tengo una duda sobre el rendimiento al momento de realizar consultas con Linq sobre el Modelo de Entity Framework, el rendimiento de las consultas se ve degradado con respecto a utilizar los famosos store procedures que siempre utilizamos con la llegada de Linq y entity FrameWork se deja de lado los store procedures?

Saludos

Diego Rojas dijo...

Que tal Alan?
Pues mira, yo en realidad en muchos casos, cuando el procedimiento es muy pesado ( muchos joins y calculos para obtener el resultado - hago un procedimiento almacenado y lo mapeo en el EF - tema que espero abarcar pronto -. Sin embargo, en SQLServer 2008 este tema esta casi parejo, es decir, esta comprobado que los sp y los queries dinámicos funcionan a una velocidad similar. En lo que si hacen diferencia los sps es en el aspecto de seguridad.

Saludos y muchas gracias por escribir

Anónimo dijo...

Hola
Recien leo el artículo, y pregunto - ¿sería correcto? si en vez de hacer referencia a la "capa de datos" (Usuario usuario=new Usuario( );) en la capa de presentacion, yo colocara en el objeto UsuarioBL de la capa de negocio una propiedad de tipo Usuario y manejarme con esa propiedad en vez de con la entidad.

Diego Rojas dijo...

Hola
Primero que todo gracias por el comentario. Si, en realidad puedes poner una propiedad que te de acceso a la entidad, lo cual haría que el UI no dependa del esquema generado. Te adjunto un link con lo que se propone para la arquitectura de una aplicacióin utilizando EF http://i.msdn.microsoft.com/cc700340.fig01_L(en-us).gif

JrBeltrant dijo...

El EF me esta gustando mucho, pero me saltan dos preguntas que debo hacer:
1. Como resuelve el EF los ataques de SqlInjecction???? es decir, es vulnerable o hay que hacer algo al respecto para darle seguridad.
2. Según la documentación el EF funciona con sqlServer, MySql y muchas más, alguien lo ha probado con MySql, sucede que mis desarrollos estan con esta BD y me gustaría saber si alguien ya lo ha utilizado.

Gracias por sus comentarios y estaré vistando el sitio para aprender y contribuir en lo que me sea posible.

Att. Jrb.

Arturo dijo...

Muy interesante la implementación en n-layers de EF. Estaré muy pendiente de todos tus artículos al respecto.

¿Cual es la solución al error del ConectionString?

Saludos

Diego Rojas dijo...

1. José, no hay problemas con sql injection, ya que la info que se ingresa a la base de datos ingresa vía instancia de objeto, entonces las expresiones sql estan encapsuladas.
2. La verdad no he probado tra base de datso diferente a SQLServer

Diego Rojas dijo...

La solución inmediata es copiar el connection string al config del componente que presenta el UI.

Gerardo dijo...

HOla, en cuánto al tema del Connection String en la capa UI... es un problema de EF ó hay alguna otra manera de especificarlo en el propio ensamblado donde está EF?

Jm dijo...

estaba leyendo tu blog y siguiendo los pasos y me encontré con el siguiente error en esta parte :S

estoy usando Visual Studio 2010 Beta

Error 1 Program 'c:\users\jesus\documents\visual studio 2010\Projects\Solution2\Cliente_WPF\obj\x86\Debug\Cliente_WPF.exe' does not contain a static 'Main' method suitable for an entry point Cliente_WPF

Googleando un rato dice que es royo del framework 4.0, pero yo cuando cree los nuevos proyectos y todo tenia seleccionado el framework 3.5 sabras porque es este error? de verdad estoy interesado en aprender a crear aplicaciones por capas

Diego Rojas dijo...

Para el UI seleccionaste una Aplicación WPF y para las otras capas librerías Windows? Debes estar seguro que la capa UI genera un ejecutable ( exe ) cuando compilas, esto lo puedes ver en el proyecto bin debug o release dependiendo del tipo de compilacion que estes haciendo.
Saludos y gracias por leer el blog

Jm dijo...

ya logre solucionar el problema anterior, no estoy seguro del todo que era lo que hice fue borrar la UI y volverla a hacer sin cambiar los nombres supongo que fue algun nombre mal referenciado :s

ahora me da otro error pero es al agregar a dos personas seguidas, creo que el problema es del ID xq estuve siguiendo la exception y llegue a un error de primary key, despues cambie el id manualmente y agrege sin problema, asi q el royo creo que es con el Id, en el articulo dice q es autogenerado pero no veo en que parte se especifica eso, espero me puedas ayudar :)

Diego Rojas dijo...

Si Jm,
debes de crear un campo llave en la tabla que se llama Id que es tipo int o BigInt y configurarlo en las propiedades de SQL para que sea auto Identity, esto hará que se genere una llave automáticamente por parte de la base de datos con lo cual no tendrás problemas de duplicación de llaves

Saludos

Buho dijo...

He seguido sus comentarios sobre EF y han sido un gran aporte
Mi duda es: Utilizando el EF como debo realizar una insercion de tipo maestro detalle?

Juanma dijo...

Buenas, acabo de leer este post, y en la parte en la que hablas del archivo de configuración app.config, cuando da error al insertar un usuario, dices la forma de arreglarlo "temporalmente", ¿Cúal sería la forma no-temporal?
Muchas gracias. Gran post!

Edgar dijo...

Perdón pero soy nuevo en EF y me parece muy interesante! Muchas gracias por esta serie de posts, son de mucha ayuda.

Estoy haciendo este ejercicio con VS2010 Profesional y he seguido paso a paso todo lo que está escrito pero tengo un problema que la verdad ya le busqué pero no sé de donde venga.

El problema surge al crear el código del boton Cuando hago la instancia de la clase Usuario:

Usuario usuario = new Usuario( );

Me marca el siguiente error:

Error 1
The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

Agregué las dos referencias: CapaDeAccesoADatos y LogicaDeNegocios pero no entiendo de donde venga el error.

¿Alguna sugerencia?

Si tienen alguna liga de programación en tres capas se los agradeceré la compartan, estoy iniciando un nuevo proyecto y quiero implementarlo junto con EF.

Muchas gracias a todos! Saludos

Diego Rojas dijo...

Hola Edgar, gracias por leer el blog. Si mira, sobre el proyecto darle botón derecho add reference y agregas una referencia al dll en el tab .NET que se llama System.Data.Entity

Saludos

Edgar dijo...

Diego, todo funciona a la perfección. Muchas gracias.

Felicidades por tu blog!!!

zitrodan dijo...

Diego, Excelente aporte, te felicito, me ha servido de mucho acerca de las dudas que tenía de como interactuar con EF y la arquitectura tradicional n-capas..

Anónimo dijo...

Hola, leyendo los comentarios he visto que se incumple el principio de separación de capas. Al principio de leer el post crei q era normal, cosa del entity framework. Pero buscando y rebuscando en otros blogs en topado con este:

http://geeks.ms/blogs/adiazmartin/archive/2010/01/18/self-tracking-en-entity-framework-4-0.aspx

Y parece que los objetos entidades se pueden poner en un proyecto aparte en la capa de lógica de negocio para asi no incumplir dicho principio.

¿Qué opinas?

Diego Rojas dijo...

Gracias por leer el blog, si lo que pasa es que este articulo estaba basado en el EF del framework 3.5 SP1, en el 4 ya existen más tipos de proyectos al respecto, sin embargo, si queres separación estricta de capas, puedes crear una capa de entidades de negocio ( POCO ) y crear mapas entre las entidades del EF y las clases POCO, claro perderías cierto funcionalidad del EF que la gente gusta utilizar, por ejemplo tal y como lo muestra el link que pusiste, el tracking del estado de las mismas

saludos

Visual Studio.NET dijo...

Hola Diego! Estuve leyendo todos tus post sobre Entinty Framework en n-capas y me parecieron muy bueno.
Te comento que al momento de ejecutarlo me lanzó el siguiente error "La conexión con nombre especificada no se encuentra en la configuración, no es apropiada para ser utilizada con el proveedor de EntityClient, o no es válida."; he estado googleando y no pude conseguir una solución.
Si me podés ayudar con la solución desde ya muchas gracias...

Diego Rojas dijo...

Hola! gracias por leer el blog. Mira, el error te da porque el string de conexión esta en la condiguración del BL. Copia el elemento del string de conexion al app.config o webconfig - depende del tipo de app que estes haciendo - y prueba de nuevo.
saludos

aandresortiz dijo...

Excelente blog Diego gracias a San Google llegue a dar a estas publicaciones sobre Entity Framework y me sirvieron de mucha ayuda, gracias y espero pronto algunas de MVC :). Sigue así.

Diego Rojas dijo...

Gracias Andrés por tomarte el tiempo para leer el blog y por los buenos comentarios :). Espero poner algo del mvc pronto :)

saludos

Matias dijo...

Hola Diego, estoy siguiendo los post sobre entity framework pero no encuentro la parte 4 y 5, podrias comentar el link para acceder, desde ya gracias y felicitaciones por el blog

Diego Rojas dijo...

Hola Matias, gracias por leer el blog. Claro, aquí van:
http://icomparable.blogspot.com/2009/05/el-entity-framework-en-una-arquitectura_06.html
Y este http://icomparable.blogspot.com/2009/09/extendiendo-el-entity-framework.html

José de Paz dijo...

Hola buen día,

Gracias a lo que escribiste acerca del EF, pude resolver el problema que me estaba sucediendo, y bueno no encontraba respuesta, mi problema sucedía por la separación de capas, y bueno ya se que es cuestión de conceptos, porque cualquiera diría: Estas en contra del modelo de n-capas o violando el concepto de n-capas.

Esto me sucedío con VS2010 y el EF4,ahora seguire el consejo que dices acerca de usar capas POCO

Saludos y muchas gracias

jose.depaz@gmail.com
http://uniescuintla.blogspot.com

Anónimo dijo...

Hola como estas como puedo sacar el atributo de un usuario como el nombre en una funcion

Diego Rojas dijo...

Hola, no se si entiendo tu pregunta, pero el nombre es una propiedad de la entidad, no una función. Las propiedades son un concepto de .net, en Java serían getter y setter

saludos

Pablo dijo...

Excelente tu aporte Diego. Muy claro y fácil de seguir. Me ha sido de gran ayuda en mis primeros pasos en EF.

Saludos y continúa así!

Diego Rojas dijo...

Gracias Pablo por tus comentarios

Anónimo dijo...

Como citó Juanma...
En la que hablas del archivo de configuración app.config, cuando da error al insertar un usuario, dices la forma de arreglarlo "temporalmente", ¿Cúal sería la forma no-temporal?

Anónimo dijo...

Diego, muchas gracias por este blog.. Como manejas el tema de que usas distintos context para cada clase de negocio?. He visto que por ahi algunos utilizan una clase de negocio Databridge haciendo que todo pase por esta clase y desde ahi se llaman los metodos de negocio. Pero la verdad no me convence o no lo entiendo al esquema.. me podes explicar como lo implementas... muchas gracias..

Anónimo dijo...

hola podria ayudarme necesito mostrar el codigo del sql en un textbox antes de guardarlo.Es autoincremental.
Mi correo es bonyantonia_1@hotmail.com

sebastian dijo...

Por lo que pude ver el EF, no termina de ser la capa de acceso a datos como la teoria manda, sino mas bien trabaja como una capa un tanto transversal a la aplicacion, ya que se dedica al transporte de entidades entre capas y ademas el acceso a los datos.

Se podría independizar esto poniendo una capa de transporte y dejar que el EF solo se dedique al acceso a los datos de forma pura y dura???