EntityFramework DB First, Model first o Code first ¿cuál EntityFramework elegir? EntityFramework nos provee tres enfoques o tres formas para crear nuestro modelo conceptual o modelo de dominio, los cuales describo a continuación: 1. DataBase First: First: Permite obtener un modelo basado en una base de datos existente, todas las clases del modelo serán generadas automáticamente a través de plantillas de generación de código T4, digamos que este flujo es muy común ya que solemos modelar en primera instancia nuestra base de datos y a lo largo del proyecto trabajamos sobre ella, nuestro modelo generado quedará almacenado en un archivo con extensión .edmx y este se podrá ver y editar en un diseñador, para actualizar nuevos cambios que surjan en nuestra base de datos. 2. Model First: First: En este enfoque creamos en primera instancia nuestro modelo conceptual a través de un Entity Data Model, y posteriormente basados en este modelo creamos nuestra base de datos, una ventaja de este enfoque es que nos concentramos en el dominio de nuestra aplicación y EF se encarga de crear la base de datos con la información que consignamos en el modelo. 3. Code First: First: Con este enfoque nos salimos un poco de lo normal, en este caso primero codificamos nuestras clases de dominio o clases POCO y luego basados en ellas creamos nuestro modelo y base de datos, solo debemos crearlas y hacer uso de DBContext y DBSet para cada clase que se creara en nuestra base de datos, para manejar las actualizaciones en nuestra DB tenemos DataBase Migrations que nos permite actualizar los cambios sobre nuestras clases. Bueno ahora que conocemos los diferentes enfoques que nos permite EntityFramework para crear nuestro modelo conceptual, me imagino que elegir uno u otro radica mucho en nuestros gustos y costumbres como desarrolladores, sin embargo también existe un factor que puede influir y es el insumo con el que contemos en el momento, es decir, si ya contamos con una base de datos creada por ejemplo, o si tenemos un modelo establecido o si simplemente ya tenemos unas clases creadas, lo importante es que sepamos que para cada uno de estos casos EF nos ofrece una solución, con esto podemos ahorrar bastante trabajo según sea nuestro caso. Por ultimo les quiero compartir una gráfica que he encontrado que podría resumir este artículo:
Bueno amigos espero este artículo les sea de utilidad a la hora de elegir un enfoque de EntityFramework, en próximos artículos veremos en detalle cada uno de los enfoques y su implementación.
[EntityFramework] [EntityFramewo rk] Iniciando con Data Base First En el artículo anterior Enfoques anterior Enfoques en EntityFramework observamos que enfoques o que flujos podemos seguir para trabajar con EF, ahora vamos a hacer doble clic sobre cada uno de los
enfoques para ver más en detalle cada uno de ellos, en primera instancia vamos a iniciar con Data Base First, que como había mencionado nos permite generar automáticamente nuestro modelo y nuestras clases Poco, teniendo como punto de referencia una base de datos previamente creada. Pues veamos cómo podemos lograr esto: Para nuestro ejemplo vamos a trabajar con la famosa base de datos Northwnd, de la cual comparto un .bk para que puedan seguir paso a paso la demo: Northwnd DB Una vez restauremos la base de datos, generamos nuestro EntityDataModel, que generará nuestro modelo conceptual y las clases poco que estarán mapeadas a él, para esto seguimos los siguientes pasos: 1. En nuestro proyecto que puede ser una librería de clases, sitio web, consola, etc. Oprimimos clic derecho y elegimos la opción agregar nuevo elemento, posteriormente filtramos los tipos de elementos por datos y por ultimo elegimos ADO.NET Entity Data Model y hacemos clic sobre el botón agregar, no sin antes darle un nombre a nuestro modelo:
2. Posteriormente nos muestra dos opciones, la primera para generar desde una base de datos existente y la otra para crear un modelo en blanco, en nuestro caso seleccionamos la primera para crear desde nuestra DB Northwnd:
3. Ahora debemos especificar los datos de conexión a nuestra base de datos, para esto hacemos clic en el botón "Nueva conexión", luego vemos como se genera una cadena de conexión y podemos elegir si mostrarla en el archivo de configuración de nuestro proyecto o no:
4. Una vez lista nuestra conexión podemos elegir que versión de EntityFramework vamos a usar, para nuestro ejemplo usaremos la versión 6 que es la última versión recientemente liberada:
5. Y para finalizar, debemos elegir los elementos de nuestra base de datos que queremos que sean incluidos en nuestro modelo:
Y nuestro resultado final es el modelo que visualizamos de inmediato, con sus respectivas relaciones, procedimientos almacenados y funciones si es que los seleccionamos para incluir, todo esto representado en un archivo con extensión .edmx, el cual si exploramos bien contiene el diagrama y además todas las clases auto generadas que corresponden a las tablas en nuestras base de datos:
Bueno amigos eso es todo por esta ocasión. Con esto damos inicio a EntityFramework DB First, en próximos artículos profundizaremos más acerca de este modelo que generamos y como interactuar con el para el acceso a datos de nuestras aplicaciones, espero les sea de utilidad.
[EntityFramework] Míralo tan fácil como quieras! dividiendo en colores tu modelo conceptual Como todos sabemos, en proyectos de gran tamaño, también tenemos por lo general un modelo de datos de gran tamaño, y que tiende a crecer con el tiempo, esto sin lugar a dudas se vuelve demasiado engorroso a la hora de comprender el diagrama y a la hora de buscar tablas y relaciones que corresponden a cierta incumbencia del sistema. Pero bueno, después del problema ahora veamos una de las soluciones que nos plantea EntityFramework al respecto: En EF podemos hacer mucho más amigable visualmente nuestro modelo, pintándolo y dividiéndolo por colores, por ejemplo podríamos colorear de verde las tablas correspondientes a seguridad, o de naranja las tablas correspondientes a las ventas y así para cada segmento de tablas, ahora veamos cómo podemos hacer esto y que tan sencillo es: Solo basta con elegir la tabla o las tablas que deseamos pintar de cierto color, abrimos el cuadro de propiedades(f4) y establecemos la propiedad FillColor seleccionando del ColorPicker el color que queremos, y así para cada tabla, de esta forma nos encontramos con un modelo divido y agrupado estratégicamente y de mucha más fácil compresión. Eso es todo, espero que este sencillo truco les sea de utilidad a la hora de ordenar mejor su modelo.
[EntityFramework] Divide y vencerás! dividiendo en varios modelos nuestro modelo conceptual Como vimos en nuestro anterior artículo, veíamos una forma que nos ofrece Entityframework a través de colores para hacer más legible nuestro diagrama a la hora de interpretarlo y analizarlo, sobre todo cuando nuestro modelo es demasiado grande y complejo, pero esto no es todo, hay otra facilidad que nos ofrece EF y es separar nuestro modelo en varios diagramas para visualizarlo mejor, esto no quiere decir que vamos a separar nuestro modelo y sus clases
generadas y ahora tengamos que acceder de forma diferente a ellas, es solo una separación visual valga la aclaración. Entonces una buena practica sería tener un diagrama principal en el cual tengamos nuestro modelo completo, y tener sub diagramas que nos modelen ciertas incumbencias del negocio, entonces podríamos tener un sub diagrama para ventas, otro para clientes, otro para proveedores y así, según lo necesitemos. Pero bueno veamos cómo podemos hacer esto en la práctica: Lo primero que debemos hacer es clic derecho sobre nuestro modelo y elegir Model Browser, con esto se nos despliega una pestaña en cual podemos ver los diagramas, las entidades del modelo y la base de datos.
Ahora en la carpeta Diagrams hacemos clic derecho y elegimos la opción "add new Diagram", con esto tenemos una plantilla en blanco, sobre la cual podemos arrastrar todas nuestras entidades para formar el diagrama que queremos.
De esta forma podemos crear los diagramas que queremos y podremos comprender y tener mayor enfoque cuando requiramos analizar el modelo correspondiente a alguna parte en específico de nuestro sistema, adicional hay una característica que vale la pena resaltar y es que si hacemos clic derecho sobre una de las entidades y elegimos la opción: "Include Related" se nos traerán al diagrama todas las entidades que tienen relación con esta, muy útil por cierto para formar el diagrama con mayor rapidez.
Y para finalizar quisiera recomendarles tener precaución al eliminar una entidad de algún diagrama, ya que si no nos fijamos bien podemos eliminar la entidad como tal de nuestro modelo, es decir eliminar la clase y cuando sincronicemos con la base de datos eliminaríamos la tabla, y hablo de cuando la eliminamos a través de la tecla suprimir, entonces les recomiendo usar shift + suprimir, si lo quieren hace por teclado o haciendo clic derecho sobre la entidad y eligiendo la opción "Remove from diagram".
Y bueno eso es todo por hoy, espero que les sea de gran utilidad para ordenar y hacer más legibles sus diagramas.
[EntityFramework] Actualizando nuestro modelo cuando surgen cambios en la base de datos Como es normal, una vez creada la base de datos de nuestro proyecto, lo más probable es que surjan muchos cambios que debamos hacer sobre ella. ya sea porque descubrimos alguna inconsistencia, por cambios del sistema o por que simplemente se agregan nuevas funcionalidades o módulos, bueno esto de entrada nos hace plantearnos una interrogante, Si ya tengo mi modelo con EF ¿cómo logro actualizar los cambios desde mi base de datos? bueno esto es algo sumamente sencillo y que ha venido mejorando en EntityFramework, como en nuestra serie de artículos sobre EF vamos a ver un paso a paso de cómo lograr esto: En primera instancia debemos tener abierto nuestro modelo y sobre el hacer clic derecho y elegir la opción "Actualizar modelo desde la base de datos", como se ve en la imagen:
Con esto se nos abrirá una ventana que contiene tres pestañas la primera con título agregar, la segunda actualizar y la tercera eliminar, y como su nombre lo indica en la pestaña agregar encontramos todos los elementos que se han agregado a la base de datos y que aún no están
mapeados a nuestro modelo o aquellos objetos que no se seleccionaron cuando se decidió crear el modelo basado en la DB:
En la segunda pestaña encontraremos todo aquellos objetos que se actualizarán con la sincronización, es decir aquellos que ya están mapeados con la base de datos, se actualizarán para obtener cambios que aún no se han mapeado:
Y por último en la tercer pestaña encontramos todos aquellos objetos que se decidieron eliminar de nuestro modelo, esto quiere decir que los elementos que seleccionemos en esta pestaña se borraran también de la base de datos, por eso debemos tener especial cuidado con esta pestaña, ya que pudimos haber eliminado alguna entidad de nuestro modelo sin darnos cuenta:
Bueno y para efectuar la sincronización hacemos clic sobre el botón "Terminar", esperamos unos segundos y enseguida podemos ver todos los cambios que realizamos en la base de datos actualizados en nuestro modelo.
Y eso es todo, una manera bastante simple y ágil para sincronizar nuestro modelo con nuestra base de datos, espero les sea de utilidad.
[EntityFramework] No tienes por qué dejar tus procedimientos almacenados en el olvido, úsalos en EF En nuestra serie de post acerca de DataBase First hemos visto varios artículos que nos guían sobre como interactuar con nuestro modelo y nuestra base de datos, y sin lugar a dudas no podemos dejar a un lado el uso de procedimientos almacenados, ya que es un objeto de nuestra base de datos al que estamos bastante acostumbrados y solemos usar a menudo, por esto vamos a dar un vistazo a como se usan en EntityFramework. Antes que nada para hacernos una idea más global de cómo se usan los stored procedures en EntityFramework cabe decir que se mapean a nuestro modelo como funciones o métodos, los cuales podemos usar normalmente con C# o el lenguaje de programación con el que estemos trabajando explícita o implícitamente, entonces podemos usar de igual forma parámetros de entrada y de salida, que es una técnica bastante utilizada por todos, y como es de esperarse también podremos obtener un valor de retorno en nuestro método. Pero bueno ahora sí, veamos como agregar procedimientos almacenados que existen en nuestra base de datos a nuestro modelo. Existen varias formas de hacerlo, y vamos a verlas a continuación: Mapear un procedimiento almacenado a una entidad en específico: En nuestro modelo podemos hacer clic sobre una de las entidades y elegir la opción "Estored Procedure Mapping", esto implica que el procedimiento será mepado directamente a nuestra entidad, y que cuando hagamos una actualización, inserción o eliminación (Depende de las que funciones que indiquemos) sobre la entidad, el código que generará EF cuando usemos Linq no será un query como habitualmente lo hace si no que generará el llamado al procedimiento almacenado enviando los parámetros indicados.
Enseguida se nos muestra la pestaña de "Mapping Detailts" en dónde encontraremos tres secciones, una para mapear un procedimiento para inserción, otra para mapear un procedimiento de actualización y por ultimo una para mapear un procedimiento de eliminación, podemos usarlas todas o solo las que necesitemos según sean nuestras necesidades, y cuando elijamos el SP que deseamos mapear enseguida se desplegarán sus parámetros y adicional podemos especificar bindings para los resultados, tal y como se muestra en la siguiente imagen:
Para terminar de mapear nuestro procedimiento almacenado, guardamos los cambios realizados en el modelo y listo! ahora podemos ver el SP mapeado como una función en el Model Browser:
Mapear una función a un procedimiento almacenado: También podemos mapear una función de EF a un procedimiento almacenado directamente, y podemos manejar varios valores de retorno, para esto debemos hacer clic derecho sobre nuestro modelo sin tocar una entidad y elegir la opción "Add New" / "Function Import" tal y como se muestra en la imagen:
Enseguida se nos mostrará la siguiente ventana que describo a continuación:
Como vemos en primera instancia debemos especificar el nombre que va a tener nuestra función, debajo tenemos una casilla de verificación "Function import is composable", que nos permite indicar si vamos a trabajar con un SP o con una función de sql server, y dependiendo de esta selección en el siguiente listado se mostraran todos procedimientos almacenados o todas las funciones que tengamos en nuestra base de datos, obviamente debemos seleccionar una. Ahora vamos a ver que opciones tenemos para retornar en nuestra función: None: Indica que la función no tendrá valor de retorno. Escalars: Indica que la función retornara un valor escalar, es decir un solo valor, el cual puede ser de diversos tipos los cuales podemos ver si seleccionamos esta opción. Complex: Indica que la función retornara un tipo complejo o Complex type, de este tipo
hablaremos más adelante, pero básicamente es un tipo que puede contener campos de varias entidades por ejemplo, o incluso campos que no corresponden a las entidades como valores calculados, si seleccionamos esta opción podemos seleccionar un tipo complejo que ya tengamos creado, o también lo podemos crear en esta misma ventana a través de la opción "Create new Complex Type" que explicaré más adelante. Entities: Indica que se va a retornar una entidad de nuestro modelo. Y por último tenemos la sección de información de columna, donde si hacemos clic en la opción "Get Column Information" podremos ver el detalle de cada columna que devuelve el procedimiento almacenado, si es que devuelve alguna columna, y es a esto cuando me refería a crear un Complex type desde esta misma ventana, ya que si hacemos clic en la opción "Create new Complex Type" automáticamente se creará un tipo complejo para la estructura de columnas que devuelve el SP. Mapear la función al procedimiento almacenado a través del Model Browser: Bueno y por ultimo también podemos hacer el mapeo del procedimiento almacenado desde el model browser, haciendo clic derecho en la carpeta "Function Imports" y eligiendo la opción "Add function import", tal y como se ve en la imagen:
Y posteriormente se nos muestra la misma ventana explicada anteriormente. Bueno y con esto damos por terminado nuestro artículo acerca del uso de procedimientos almacenados en EntityFramework, espero les sea de gran utilidad y veamos que no se trata de comparar EF vs Stored procedures como me han preguntado algunas personas, si no de usarlos en conjunto para obtener un óptimo desempeño.
[EntityFramework] Trabajando con enumeraciones Sin lugar a duda, un recurso ofrecido por el .Net Framework y muy utilizado por todos son las famosas enumeraciones o enum, que básicamente son un conjunto de constantes con nombre, que nos permite hacer nuestro código más legible y organizado, además de evitar confusiones con respecto a los valores que admite determinada variable, y sin dejar a un lado la ventaja de poder usar el Intellisense para la asignación de valores. Para mayor detalle observar msdn Enum referencia. Y bueno el uso entonces de los enums, en la mayoría de los casos supone también que se debe persistir su valor en la base de datos, y que bien que nuestro ORM pudiera manejar por si solo el trabajo con enumeraciones, sin que esto implique esfuerzo alguno para el desarrollador ¿no creen? Pues bueno a partir de la versión 5 de EntityFramework se incorporó el soporte de enumeraciones, y vaya que es una gran característica, ya que podemos trabajar con el tipo del enum como estamos acostumbrados a través de una propiedad de nuestra entidad, y EF se encarga de mapear su valor y guardarlo en la base de datos, y a continuación vamos a ver
cómo podemos lograrlo: Lo primero que debemos hacer es abrir nuestro modelo, y abrir el Model Browser, en el cual encontraremos una carpeta llamada Enum types, sobre la cual haremos clic derecho y elegiremos la opción "Add New Enum type", tal como se muestra en la imagen:
Enseguida se nos mostrara la siguiente ventana, en la cual debemos especificar las constantes que tendrá nuestra enumeración:
En primera instancia debemos especificar el nombre que tendrá la enumeración, y el tipo del cual heredara si Int 16, 32 ó 64, Byte o SByte esto según la longitud de los números que se vayan a asignar a las constantes. Y posteriormente debemos indicar cuál será el listado de constantes de la enumeración y que valor le corresponderá a cada una, y ya con esta información podemos terminar la creación del enum, sin embargo en la última parte del cuadro de dialogo tenemos dos opciones más, las cuales explicaré a continuación: Set Flags attribute: Como todos sabemos o si no lo sabes aún te contextualizo, cuando creamos a través de código una enumeración la podemos decorar con el atributo [Flags], esto indica que la enumeración podrá manejar combinaciones, es decir se puede asignar su valor con más de una opción, yo podría asignar como valor, en nuestro caso por ejemplo los valores TarjetaCredito y TarjetaDebito que en código C# sería algo como esto:
FormaPago formPago = FormaPago.TarjetaCredito | FormaPago.TarjetaDebito; Reference external type: Además de crear una nueva enumeración también podemos usar una ya existente, para eso este campo, en el cual debemos especificar el NameSpace y el nombre del enum, para que sea usado por EntityFramework. Y listo para crear nuestra enumeración oprimimos el botón OK, y ya tenemos nuestro enum creado para ser utilizado, ahora podemos hacer clic en cualquiera de los campos de cualquier entidad y abrimos el cuadro de propiedades correspondiete(F4) y en el campo "type" veremos que ya podemos escoger como tipo la enumeración que acabamos de crear:
Bueno y con esto damos por terminado nuestro artículo acerca del cómo trabajar con enumeraciones en EntityFramework, espero les sea de gran utilidad y ya queda criterio propio como explotar todas las ventajas que nos ofrece.
[EntityFramework] Usando datos Geoespaciales Una de las principales características introducidas en Sql Server 2008 fue el soporte para trabajar con datos geoespaciales, a través del soporte para los tipos Geography y Geometry, y una buena pregunta sería, ¿podemos trabajar en EntityFramework con estos tipos de datos? pues bueno la repuesta es si, a partir de la versión 5 de EF esta característica fue liberada, con soporte para ambos tipos, y es de gran utilidad, ya que quizás podía significar una limitante a la hora de decidir usar como ORM EntityFramework, si nuestro sistema iba a trabajar con este tipo de información, pero bueno veamos en el listado de tipos de datos de EF como aparecen estos tipos de datos:
Como podemos ver, para ambos se muestran los mismos tipos respectivamente, y creo que hasta aquí surge otra interrogante, ¿Cuál es la diferencia entre Geography y Geometry entonces? respondamos a esta pregunta definiendo cada uno: Geography: Tipo de dato espacial que tiene la capacidad de almacenar datos elipsoides como lo son por ejemplo la coordenadas de latitud y longitud. Geometry: Tipo de dato espacial que tiene la capacidad de almacenar un sistema de coordenadas plano. Y adicional cito esta definición: Geometry and Geography are a bit different. Geometry deals with planar data. Geometry is well documented under the Open Geospatial Consortium (OGC) Specification. Geography deals with ellipsoidal data, taking in mind the curvature of the earth when performing any calculations. SQL introduced spatial support for these two types in SQL Server 2008. The SQL implementation supports all of the standard functions outlined in the OGC spec.
Y bueno amigos eso es todo, espero les sea de utilidad y puedan tener un recurso del cual echar mano cuando se les presente algún requerimiento en algún sistema con respecto a manejo de información espacial. Adicional les quería compartir estas referencias, por si quieren profundizar más acerc a del tema:
Tipos espaciales en EntityFramework
Spatial types in the EntityFramework
[EntityFramework] Resumen DataBase First Hola amigos, les comparto el resumen de todo lo que aprendimos en esta serie de artículos acerca de Entity Framework DataBase first, espero les sea de utilidad:
Enfoques en Entity Framework Conocimos los tres enfoques que tenemos en Entity Framework, DataBase first, Model first y code first, y tuvimos un punto de referencia para elegir uno de ellos.
Iniciando con DataBase first
Aprendimos a crear nuestro modelo conceptual a partir de nuestra base de datos.
Míralo tan fácil como quieras! dividiendo en colores tu modelo conceptual Vimos una característica que nos facilita mucho el entendimiento de nuestro modelo conceptual como lo es la división en diferentes colores.
Divide y vencerás! dividiendo en varios modelos nuestro modelo conceptual Aprendimos a dividir nuestro modelo conceptual en varios sub modelos, con el fin de organizarlo mejor y facilitar su entendimiento y manejo.
Actualizando nuestro modelo cuando surgen cambios en la base de datos Hicimos un ejemplo de cómo actualizar nuestro modelo cuando surgen cambios en la base de datos.
No tienes por qué dejar tus procedimientos almacenados en el olvido, úsalos en EF Conocimos las formas de cómo trabajar con procedimientos almacenados en EntityFramework.
Trabajando con enumeraciones Observamos el soporte para manejo de enumeraciones que nos ofrece Entity Framework.
Usando datos Geoespaciales Y para terminar observamos el soporte para trabajar con datos geoespaciales que nos brinda Entity
[EntityFramework] Iniciando con Code First Otro de los enfoques que nos ofrece Entity Framework es Code First, este es un enfoque en el cual se deja a un lado el diseñador de modelo y con ello toda su facilidad visual de la que hablamos en nuestra serie de artículos anteriores Enfoque Data Base First, sin embargo nos ofrece como los otros enfoques grandes ventajas si lo usamos en el escenario adecuado y un buen punto de referencia para saber si se trata del escenario adecuado es ¿Qué enfoque elegir? En Code First primero codificamos y luego generamos nuestra base de datos en base al código que hemos creado, un poco en contra de lo que estamos acostumbrados no? ya que por lo general modelamos en primera instancia y luego implementamos, sin embargo, puede darse el caso en algún proyecto que ya tengamos todas las entidades de dominio creadas por cualquier motivo, pues en este caso nos viene perfecto el uso de Code First, ya que vamos a reutilizar las entidades de dominio que ya tenemos y podemos usarlas para crear nuestra base de datos, ahí encontramos una ventaja por ejemplo, y digamos que hablando un poco más orientado a los gustos de los desarrolladores, para las personas que no son amantes del código auto generado, de un diseñador y que prefieren codificar ellos mismos la totalidad de su código, es la mejor elección. Bueno y ahora nos surge otra duda, ¿Cómo hace Entity Framework Code First para crear la base datos y mapearla con mis entidades de dominio? Como ya vimos en artículos anteriores en EF se trabaja con un Contexto (Context), el cuál
agrupa todos los objetos de nuestro modelo conceptual, bueno para code first es igual y es el primer objeto que debemos crear para generar nuestra base de datos, entonces en el constructor de nuestro contexto podemos pasar como parámetro el nombre que queremos darle a la DB una vez se cree, o también podemos pasar como parámetro la cadena de conexión para nuestra DB, o simplemente no enviamos parámetros en el constructor y siendo así code first auto generará el nombre usando el name space en cual se encuentra el contexto y el nombre de la clase del mismo, algo como eso: NameSpace.ContextClassName Y para crear tablas con sus respectivas primary y foreign key y demás objetos usa algunas convenciones, las cuales podemos encontrar en el siguiente enlace: Code First Conventions Adicional quiero compartirles esta imagen que resume el proceso de creación de la base de datos:
Y para terminar quiero compartirles un par de conceptos fundamentales a la hora de trabajar con Code first y que vamos a ver muy a menudo en nuestra serie de artículos de Code First: DbContext: Será el objeto que agrupará todos los elementos de nuestro modelo conceptual y manejará el mapeo de cada uno ellos con su par en la base de datos, incorpora el patrón unidad de trabajo y el patrón repositorio, aquí les dejo la referencia de msdn: DbContext DbSet: Comúnmente usado como tipo de propiedades al interior de una clase que hereda del tipo DbContext, este recibe un tipo genérico el cual representa una entidad de nuestro dominio, de esta forma habilita las operaciones CRUD para la entidad especificada. Aquí les dejo la referencia de msdn: DbSet DataAnotations: Serie de atributos con los cuales se pueden decorar las entidades del dominio y sus propiedades, permiten especificar características como longitud, exclusiones e mapeo, primary y foreign key, etc. Aquí les dejo la referencia de msdn: Code First Data Annotations DataBase Migrations: Permite actualizar nuestra base de datos cuando existan cambios en
nuestras entidades de dominio. Aquí les dejo la referencia de msdn: DataBase Migrations Bueno y eso es todo, espero esta introducción a Entity Framework Code First sea de gran utilidad para ustedes y despeje muchas dudas, en artículos posteriores veremos más en detalle la forma de trabajo e implementación. Saludos y buena suerte!
[EntityFramework] Creando nuestra base de datos, basados en nuestro contexto Luego de ver en nuestro anterior artículo Iniciando con Code First una introducción y un acercamiento a Entity Framework Code First, y de comprender su filosofía de trabajo, ahora vamos a ver cómo es su implementación y forma de trabajo, para esto vamos a iniciar con la creación de nuestras entidades de dominio las cuales nos servirán para toda nuestra serie de artículos de este enfoque de EF, y luego crearemos nuestro contexto, el cual como ya sabemos nos servirá para interactuar con nuestra base de datos. En primera instancia vamos a crear dos entidades de dominio, las cuales en un escenario real de utilización de EF Code First podríamos partir de que dichas entidades ya existen, nuestras entidades serán Producto y Categoría y las vamos a crear dentro de un proyecto de tipo librería de clases el cual recibirá el nombre de Dominio.
1: 2: 3: 4: 5: 6: 7: 8:
public class Producto { public int Id { get; set; }
1: 2: 3: 4: 5: 6: 7: 8:
public class Categoria { public int Id { get; set; }
public string Nombre { get; set; } public string Descripcion { get; set; } }
public string Nombre { get; set; } public string Descripcion { get; set; } }
Perfecto esas clases tan simples serán las entidades de dominio con las que trabajaremos en nuestro ejemplo, ahora vamos a habilitar estas entidades para que a través de ellas podamos en primera instancia crear nuestra base de datos y posteriormente interactuar entre dominio y DB mediante el mapeo generado, para esto creamos un contexto el cual contenga propiedades de tipo DBSet
para cada entidad:
1: 2: 3: 4: 5: 6:
class Context : DbContext { public Context() : base("Productos") { }
7: 8: 9: 10: 11:
public DbSet Productos { get; set; } public DbSet Categorias { get; set; } }
Y listo, con esto tenemos una infraestructura básica para lograr crear nuestra base de datos basados en las entidades de dominio que creamos, un aspecto a tener en cuenta en el contexto que acabamos de crear es que estamos pasando como parámetro al constructor el nombre que va a tener nuestra base de datos, y es importante especificar la cadena de conexión en el archivo app.config de nuestro proyeto, para tener los datos de conexión al servidor:
1: 2: 5: Y para terminar con nuestro ejemplo, vamos a crear en nuestra solución (.sln) un proyecto de tipo consola, en el cual probaremos si funciona correctamente nuestro contexto, para esto agregamos la referencia a nuestro proyecto de dominio, para poder acceder al contexto, hacemos el respectivo using y por ultimo copiamos este fragmento de código en el método main de la clase Program de nuestro proyecto de consola:
1: class Program 2: { 3: static void Main(string[] args) 4: { 5: using (var contexto = new Context()) 6: { 7: var producto = new Producto {Id = 1, Nombre = "Jabón", Descripcion = "Producto para el aseo del hogar" }; 8: contexto.Productos.Add(producto); 9: contexto.SaveChanges(); 10: } 11: } 12: } Ahora ejecutamos para probar, y efectivamente vemos que se ha creado nuestra base de datos, con el nombre que indicamos en el constructor, tal cual con la estructura de nuestra entidades y además se ha agregado el producto que indicamos en la tabla Productos, como podemos observar si depuramos la primer vez que ejecutamos la app se demora un tiempo considerable en agregar el producto ya que en ese momento no existe la Db y por lo tanto se crea, pero en las ejecuciones que hagamos en adelante el tiempo será muy corto. Bueno y con esto damos por terminado nuestro ejemplo de cómo crear nuestra base de datos basados en un contexto previamente creado, sin embargo surgen algunas dudas como: ¿Cómo se logran crear relaciones de diferentes tipos entre las tablas? ¿Cómo doy longitud a los
campos de la tabla y demás características? pues bien en próximos artículos iremos profundizando y explicando estos temas, espero les sea de utilidad.
[EntityFramework] Configurando nuestras entidades de dominio con Data Annotations En nuestro artículo anterior Creando nuestra base de datos, basados en nuestro contexto surgieron algunas interrogantes acerca de cómo establecer la longitud máxima para nuestros campos en la base de datos, o cómo darles un nombre diferente al de la propiedad, o cómo darles un tipo en específico, o cómo especificar si permiten valores nulos o no, o cómo crear relaciones entre las tablas, entre otras interrogantes que pueden surgir, pero bueno en este artículo vamos a ver cómo podemos lograr este tipo de cosas a través de Data Annotations, que no son más que atributos con los cuales podemos decorar nuestras entidades y propiedades para que tengan ciertas características, para quienes han trabajado con Asp.Net MVC funciona de igual forma que los Data Annotations que podemos usar para los modelos y de hecho hay unas en común para EF y MVC cómo por ejemplo el atributo Required que indica si una propiedad es requerida o no. Cómo vimos en nuestro artículo anterior para una configuración básica no es necesario usar Data Annotations ya que Entity Framework Code First trabaja con convención sobre la configuración, es decir las clases que sigan con la convención que propone EF serán mapeadas sin problemas, de lo contrario se debe usar Data Annotations o Fluent API para establecer la configuración. Ahora veamos algunos ejemplos de cómo configurar nuestras entidades de dominio usando Data Annotations, para esto usaremos las entidades de dominio del artículo anterior. Para crear relaciones entre tablas y por normalización de base de datos cada tabla debe tener una clave primaria que la identifique únicamente, como vimos en el ejemplo anterior nuestras entidades tienen un campo llamado Id, y es por esto que cuando se generó la tabla en la DB se creó este campo como primary key, y es a esto cuando me refería a convención sobre la configuración, en este caso por ejemplo EF busca en la entidad un campo que se llame Id o que contenga esta palabra y a través de esta convención sabe que este campo será la clave primaria de la tabla, y por eso decía anteriormente también que si no se cumplían con las convenciones se debería usar Data Annotations o Fluent API para el configurar, por ejemplo si en mi siguiente entidad mi clave primaria será el campo Codigo que cómo vemos no contiene la palabra Id debemos usar el atributo [Key] para especificarla explícitamente:
[Table("Productos")] public class Producto { [Key] public int Codigo { get; set; } [Required] [Column("Nombre", TypeName = "varchar", Order = 2)] public string Nombre { get; set; } [MaxLength(100), MinLength(10)] public string Descripcion { get; set; } [NotMapped] public string CodigoIso { get; set; } } Cómo podemos ver decoramos la propiedad Codigo con el atributo [Key] con esto le estamos diciendo a Entity Framework que esta será la clave primaria de la tabla, y podemos ver una serie de atributos que hemos usado y que explicare a continuación:
[Table("Productos")] : Permite asignar un nombre en específico a la tabla que se generará a partir de la entidad, recordemos que si no se usa este atributo Entity Framework asume que el nombre de la tabla será el plural del nombre de la entidad por ejemplo para la entidad Producto su tabla correspondiente recibirá el nombre de Productos. [Required] : Permite indicar si un campo es requerido o no, es decir si el campo en la tabla permitirá valores nulo o no, lo que conocemos como Null o Not Null. [Column] : Se usa para indicar información correspondiente a una columna de la tabla, su constructor posee dos sobre cargas en las cuales podemos especificar nombre de la columna en caso de que queramos especificar un nombre diferente al de la propiedad de la entidad, tipo de la columna y orden en el que aparecerá en la tabla. [MaxLength] : especifica la longitud máxima del campo en la base de datos. [MinLength] : especifica la longitud mínima del campo en la base de datos. [NotMapped] : Puede darse el caso que por algún motivo no deseemos mapear alguna propiedad de alguna entidad de dominio a nuestra base de datos ya que solo la queremos tener en nuestra entidad para usarla en nuestra lógica y no queramos persistir la propiedad a la base de datos. Este atributo nos ayuda con esto, cuando EF encuentre alguna propiedad decorada con este atributo simplemente la omitirá y no la tendrá en cuenta para la creación de la DB. Bueno y con esto damos por terminado nuestro artículo de como configurar nuestras entidades de dominio a través de Data Annotations. Cómo mencione antes existe otra forma de hacer la configuración y es a través de Fluent Api, tema que trataremos en el próximo artículo de esta serie de Entity Framework Code First, espero les sea de interés y utilidad. Para observar todos los Data Annotatiosn disponibles revisar la documentación del name space System.ComponentModel.DataAnnotations
[EntityFramework] Configurando nuestras entidades de dominio con Fluent API Cómo apreciamos en nuestro artículo anterior Configurando nuestras entidades de dominio con Data Annotations logramos configurar nuestras entidades de dominio a través de Data Annotations, con esto logramos definir características particulares de entidades y propiedades a la hora de ser mapeadas para la creación de la base de datos, esta es una forma de hacerlo, pero no la única que nos brinda Entity Framework Code First. En este artículo vamos a ver cómo podemos hacer lo mismo pero esta vez usaremos Fluent API, que nos permite hacer este tipo de configuraciones de una forma centralizada, teniendo acceso a cada entidad que tengamos en nuestro contexto y usando métodos encadenados y expresiones lambda para realizar la configuración. Ahora vamos a implementar la misma configuración del ejemplo anterior dónde usamos Data Annotations, con Fluent API para que podamos compara r más fácil cómo es el trabajo con cada una, y en base a esto tomar una elección personal de cuál usar. Lo primero que debemos hacer para usar Fluent Api, es sobre escribir el método OnModelCreating de nuestro contexto, ya con esto al interior de este método podremos realizar las configuraciones sobre las entidades, tal y cómo se muestra a continuación:
public class Context : DbContext
{ public Context() : base("Productos") { } public DbSet Productos { get; set; } public DbSet Categorias { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Aquí haremos nuestras configuraciones con Fluent API. base.OnModelCreating(modelBuilder); } } Cómo vemos ahora el método OnModelCreating recibe el parámetro modelBuilder de tipo DbModelBuilder, es con esta clase que lograremos hacer todas las configuraciones que necesitamos, ahora sí vamos a ver como lograr dichas configuraciones, las cuales haremos sobre la entidad Producto, la cual usamos en nuestro ejemplo anterior de Data Annotations:
[Table("Productos")] public class Producto { [Key] public int Codigo { get; set; } [Required] [Column("Nombre", TypeName = "varchar", Order = 2)] public string Nombre { get; set; } [MaxLength(100), MinLength(10)] public string Descripcion { get; set; } [NotMapped] public string CodigoIso { get; set; } } Ahora homologaremos todo lo que hicimos con Data Annotations a través de Fluent Api, de la siguiente manera:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Aquí haremos nuestras configuraciones con Fluent API. // Especificar el nombre de una tabla. modelBuilder.Entity().Map(m => m.ToTable("Productos")); // establecer una primary key. modelBuilder.Entity().HasKey(c => c.Codigo); // Definir un campo como requerida. modelBuilder.Entity().Property(c => c.Nombre).IsRequire d();
// Definir el nombre de un campo. modelBuilder.Entity().Property(c => c.Nombre).HasColumn Name("Nombre"); // Definir el tipo de un campo. modelBuilder.Entity().Property(c => c.Nombre).HasColumn Type("varchar"); // Definir el orden de un campo. modelBuilder.Entity().Property(c => c.Nombre).HasColumn Order(2); // Definir el máximo de caracteres permitidos para un campo. modelBuilder.Entity().Property(c => c.Descripcion).HasM axLength(100); // indicar que no se debe mapear una pripiedad a la base de datos . modelBuilder.Entity().Ignore(c => c.CodigoIso); base.OnModelCreating(modelBuilder ); } Como podemos ver, hemos homologado las instrucciones de primary key, nombres, requerido y demás características a través de Fluent Api, con esto podríamos quitar los Data Annotations de nuestra entidad de dominio Producto, y una vez se inicialice la base de datos se tendrán en cuenta las configuraciones especificadas en el método OnModelCreating. Para terminar con el artículo quisiera darles un tip, para el trabajo con Code First Fluent Api, de una forma más ordenada, ya que como vemos la codificación en el método OnModelCreating puede crecer bastante ya que allí va la configuración para cada entidad, por esto una buena práctica es separar en clases la configuración de cada entidad, con esto logramos un código más ordenado y más reutilizable, ahora veamos cómo hacerlo: Para esto sólo debemos crear una clase que herede de EntityTypeConfiguration y en el constructor de esta clase codificar las configuraciones tal y como lo hicimos en el método OnModelCreating, cómo se muestra a continuación:
public class ProductoMappings : EntityTypeConfiguration { public ProductoMappings() { // Especificar el nombre de una tabla. this.Map(m => m.ToTable("Productos")); // establecer una primary key. this.HasKey(c => c.Codigo); // Definir un campo como requerida. this.Property(c => c.Nombre).IsRequired(); // Definir el nombre de un campo. this.Property(c => c.Nombre).HasColumnName("Nombre"); // Definir el tipo de un campo. this.Property(c => c.Nombre).HasColumnType("varchar");
// Definir el orden de un campo. this.Property(c => c.Nombre).HasColumnOrder(2); // Definir el máximo de caracteres permitidos para un campo. this.Property(c => c.Descripcion).HasMaxLength(100); // indicar que no se debe mapear una pripiedad a la base de datos . this.Ignore(c => c.CodigoIso); } } Haríamos estos para cada entidad, y en el método OnModelCreating sólo agregaríamos la configuración que acabamos de crear, de la siguiente forma:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Aquí haremos nuestras configuraciones con Fluent API. modelBuilder.Configurations.Add(new ProductoMappings()); base.OnModelCreating(modelBuilder ); } Y para despedirme quisiera anotar que un método de configuración no excluye al otro, es decir podríamos usar configuración a través de Data Annotations y también a través de Fluent Api sin ningún problema. Y bueno eso es todo espero les sea de utilidad y de interés este tema de configuración de entidades de dominio a través de Entity Framework Code First Fluent Api.
[EntityFramework] Configurar una relación uno a uno en Code First En artículos anteriores, vimos cómo configurar nuestras entidades de dominio a través de Data Annotations y a través de Fluent Api, ahora vamos a ver cómo configurar diferentes relaciones en la base de datos mediante estas dos alternativas, en primera instancia vamos a ver cómo configurar una relación de uno a uno entre las entidades Producto y Categoria. Relación de uno a uno mediante Data Annotations: Nuestra entidad Categoria será de la siguiente forma:
public class Categoria { public int Id { get; set; } [MaxLength(100)] public string Nombre { get; set; } [MaxLength(200)] public string Descripcion { get; set; } [Required] public virtual Producto Producto { get; set; } }
Entonces para nuestro ejemplo supondremos que un producto solo puede tener una categoría, y para configurar la relación a través de Data Annotations hacemos lo siguiente:
[Table("Productos")] public class Producto { [Key] public int Codigo { get; set; } [Required] [Column("Nombre", TypeName = "varchar", Order = 2)] public string Nombre { get; set; } [MaxLength(100), MinLength(10)] public string Descripcion { get; set; } [NotMapped] public string CodigoIso { get; set; } [ForeignKey("Categoria")] public int IdCategoria { get; set; } public virtual Categoria Categoria { get; set; } } Como podemos ver en nuestra entidad Producto creamos una propiedad de tipo entero llamada IdCategoria, y la decoramos con el atributo ForeignKey el cual nos indica que esta propiedad nos servirá para relacionarla con otra entidad, y vemos que en su constructor especificamos la palabra "Categoria", que hace alusión a la propiedad virtual que nos sirve para configurar la relación con la entidad Categoria, de esta forma una vez se cree la base de datos se creara la relación de uno a uno. Para probar esto podemos crear una aplicación de consola y escribir el siguiente código en la clase Program:
class Program { static void Main(string[] args) { var categoria = new Categoria { Id = 1, Nombre = "Lacteos", Descr ipcion = "Productos lacteos" }; var producto = new Producto { Codigo = 1, Nombre = "Leche", Descr ipcion = "Producto Lacteo", Categoria = categoria }; using (var contexto = new Context()) { contexto.Productos.Add(producto); contexto.SaveChanges(); } } } Y observaremos que tan sólo agregando el producto a la base de datos también se agregara la categoría correspondiente en su respectiva tabla y con sus relaciones correspondientes. Ahora vamos a ver como lo podemos hacer pero esta vez usando Fluent Api.
Relación de uno a uno mediante Fluent Api: Para configurar la relación a través de Fluent Api, creamos una clase de configuración para la entidad Categoria o lo hacemos directamente en el contexto como vimos en el artículo Configurando nuestras entidades de dominio con Fluent Api :
public class CategoriaMappings : EntityTypeConfiguration { public CategoriaMappings() { // Crear relación con la entidad Producto. this.HasRequired(c => c.Producto).WithRequiredPrincipal(e => e.Ca tegoria); } } Como vemos homologamos el código planteado anteriormente con Data Annotations, indicando que en la entidad categoría se requiere un producto y de igual forma en la entidad productos se requiere una categoría. Y bueno amigos, eso es todo, espero les sea de utilidad y de interés este post acerca de relación uno a uno en Entity Framework code First, en próximos artículos observaremos cómo configurar otros tipos de relaciones.
[EntityFramework] Configurando una relación de uno a muchos en Code First En el artículo anterior vimos cómo configurar una relación de uno a uno en Code First usando Data Annotations y Fluent Api, en esta ocasión vamos a ver cómo configurar una relación de uno a muchos usando las mismas entidades de dominio Producto y Categoria. Relación de uno a muchos mediante Data Annotations: Nuestra entidad Producto será de la siguiente forma:
[Table("Productos")] public class Producto { [Key] public int Codigo { get; set; } [Required] [Column("Nombre", TypeName = "varchar", Order = 2)] public string Nombre { get; set; } [MaxLength(100), MinLength(10)] public string Descripcion { get; set; } [NotMapped] public string CodigoIso { get; set; } [ForeignKey("Categoria")] public int IdCategoria { get; set; }
public virtual Categoria Categoria { get; set; } } Cómo ven agregamos IdCategoria y especificamos que se trata de la clave foránea con respecto a la entidad categoria, de igual forma agregamos la propiedad Categoria de tipo Categoria que representa la relación, y a continuación en nuestra entidad Categoria agregaremos una colección de tipo Producto para indicar que una categoría puede tener uno o muchos productos:
public class Categoria { [Key] public int Id { get; set; } [MaxLength(100)] public string Nombre { get; set; } [MaxLength(200)] public string Descripcion { get; set; } [Required] public virtual ICollection Producto { get; set; } } Y con esto tenemos configurada nuestra relación de una a muchos entre Productos y Categorías a través de Data Annotations, ahora para probar la configuración podemos crear una app de consola y copiar el siguiente código en la clase program:
class Program { static void Main(string[] args) { var categoria = new Categoria { Id = 1, Nombre = "Lacteos", Descr ipcion = "Productos lacteos" }; var producto = new Producto { Codigo = 1, Nombre = "Leche", Descr ipcion = "Producto Lacteo", Categoria = categoria }; var producto2 = new Producto { Codigo = 2, Nombre = "Queso", Desc ripcion = "Producto Lacteo", Categoria = categoria }; using (var contexto = new Context()) { contexto.Productos.Add(producto); contexto.Productos.Add(producto2); contexto.SaveChanges(); } } } Relación de uno a muchos mediante Fluent Api: Ahora vamos a configurar la relación de uno a muchos entre Productos y Categorías, pero esta vez vamos a usar Fluent Api para lograrlo:
public class Context : DbContext { public Context() : base("Productos") { } public DbSet Productos { get; set; } public DbSet Categorias { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Aquí haremos nuestras configuraciones con Fluent API. modelBuilder.Configurations.Add(new ProductoMappings()); modelBuilder.Entity() .HasRequired(c => c.Categoria) .WithMany(c => c.Productos) .HasForeignKey(c => c.IdCategoria); base.OnModelCreating(modelBuilder); } }
Cómo vemos en el método OnModelCreating especificamos la relación a través de Fluent Api, dónde indicamos la relación partiendo la entidad Producto e indicamos el WithMany con Categoría. Y bueno amigos, eso es todo, espero les sea de utilidad y de interés este post acerca de relación uno a muchos en Entity Framework code First, en el próximo artículo observaremos cómo configurar una relación de muchos a muchos, para terminar con el tema de relaciones y seguir con otros temas.