lunes, 27 de enero de 2014

[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 { getset; }
 
        [Required]
        [Column("Nombre", TypeName = "varchar", Order = 2)]
        public string Nombre { getset; }
 
        [MaxLength(100), MinLength(10)]
        public string Descripcion { getset; }
 
        [NotMapped]
        public string CodigoIso { getset; }
    }

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

Saludos y buena suerte!

lunes, 20 de enero de 2014

[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:  public class Producto
   2:  {
   3:      public int Id { get; set; }
   4:   
   5:      public string Nombre { get; set; }
   6:   
   7:      public string Descripcion { get; set; }
   8:  }

   1:  public class Categoria
   2:  {
   3:       public int Id { get; set; }
   4:   
   5:       public string Nombre { get; set; }
   6:   
   7:       public string Descripcion { get; set; }
   8:  }

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<T> para cada entidad:

   1:  class Context : DbContext
   2:  {
   3:       public Context() : base("Productos")
   4:       {
   5:              
   6:       }
   7:   
   8:       public DbSet<Producto> Productos { get; set; }
   9:   
  10:       public DbSet<Categoria> Categorias { get; set; }
  11:  }

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:  <connectionStrings>
   2:      <add name="ProductosDBConnectionString"
   3:      connectionString="Data Source=TAVOPC\SQLEXPRESS;Initial   Catalog=Productos;Integrated Security=true;"
   4:      providerName="System.Data.SqlClient"/>
   5:  </connectionStrings>

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.

Saludos y buena suerte!

domingo, 12 de enero de 2014

[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!

martes, 7 de enero de 2014

[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.

  • Aprendimos a crear nuestro modelo conceptual a partir de nuestra base de datos.


  • Vimos una característica que nos facilita mucho el entendimiento de nuestro modelo conceptual como lo es la división en diferentes colores.


  • Aprendimos a dividir nuestro modelo conceptual en varios sub modelos, con el fin de organizarlo mejor y facilitar su entendimiento y manejo.


  • Hicimos un ejemplo de cómo actualizar nuestro modelo cuando surgen cambios en la base de datos.


  • Conocimos las formas de cómo trabajar con procedimientos almacenados en EntityFramework.


  • Observamos el soporte para manejo de enumeraciones que nos ofrece Entity Framework.


  • Y para terminar observamos el soporte para trabajar con datos geoespaciales que nos brinda Entity Framework.
Saludos y buena suerte!

lunes, 6 de enero de 2014

[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) SpecificationGeography 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 acerca del tema:


Saludos y buena suerte!

[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.

Saludos y buena suerte!

viernes, 3 de enero de 2014

[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.

Saludos y buena suerte!