Mostrando entradas con la etiqueta CodeFirst. Mostrar todas las entradas
Mostrando entradas con la etiqueta CodeFirst. Mostrar todas las entradas

domingo, 3 de abril de 2016

Dapper vs EntityFramework, debo usar un MicroOrm o un Orm?


En muchos de nuestros proyectos hemos usado un Orm para lograr mapear nuestro modelo de datos a nuestros objetos y estructura de clases de nuestra aplicación, logrando con esto resolver el acceso y persistencia de datos sin mucho esfuerzo y poder enfocarnos en lo que verdaderamente nos importa, el dominio del negocio.



Los Orm han tomado mucha fuerza y actualmente son usados en la mayoría de aplicaciones dado las facilidades y bondades que ofrecen, Orms como Nhibernate, EntityFramework, Hibernate, Telerik Data Access, son ejemplos de Orms bastante populares y usados en la actualidad, debido a las facilidades que ofrecen y buenas prácticas y patrones que encapsulan.

Pese a esto siempre se ha discutido con respecto al rendimiento que estos nos ofrecen y cómo pueden afectar el desempeño de nuestras aplicaciones, debido a las facilidades y funcionalidades que ofrecen se vuelven bastante robustos para preparar y acceder a la información. Por ejemplo EntityFramework está basado sobre la arquitectura de Ado.Net lo cual sugiere que tenemos una capa intermedia, que obtiene el resultado a través de los componentes de este y posteriormente mapea el resultado a un objeto de nuestra aplicación, este proceso sugiere algunos milisegundos más en cada transacción.

Ahora, que pasa si tuviéramos una alternativa un poco más liviana y rápida que sacrifique algunas facilidades y características para garantizar el rendimiento en el acceso a datos? pues de esto se trata un MicroOrm, este nos permite realizar un mapeo de nuestro modelo relacional a objetos de nuestra aplicación, solo que lo hace de una forma más simple y sin algunas características como por ejemplo manejo de relaciones entre tablas, manejo de concurrencia, cargas por demanda, diseñador del modelo, etc.

Entre los MicroOrm más famosos encontramos los siguientes:
  • PetaPoco
  • Insight
  • NPoco
  • Dapper (Se puede decir que este es el MicroOrm más conocido y usado, debido a que se ha comprobado que es el que mejor rendimiento tiene, tan solo un milisegundo más que una consulta directamente con Ado.Net, adicional este es el MicroOrm usado por el reconocido foro StackOverflow, para soportar su robusta arquitectura)
Ahora que ya conocemos que es un micro Orm y sabemos cuál es su principal diferencia con un Orm, vamos a ver cómo funciona y cómo es su implementación, para esto vamos a usar Dapper, y adicional vamos a realizar una serie de comparaciones de rendimiento y de codificación con EntityFramework.

Para nuestro ejemplo vamos a usar la conocida base de datos Northwnd, la cual puedes descargar del siguiente enlace: https://northwinddatabase.codeplex.com/

Posteriormente vamos a crear en Visual Studio un nuevo de proyecto de tipo consola y en la clase Program, vamos a empezar a codificar el ejemplo.

Para iniciar vamos a abrir la consola del administrador de paquetes Nuget y vamos a ejecutar el siguiente comando para instalar el paquete de Dapper:

Install-Package Dapper -Version 1.42.0

Y hacemos el Using del NameSpace Dapper en la clase Program, con esto se agregan una serie de métodos de extensión a la clase SqlConnection las cuales nos permiten usar el MicroOrm para interactuar con la base de datos.

Para la conexión a la base de datos a través de Dapper solo necesitamos especificar la cadena de conexión, para esto crearemos una constante en clase Program en la cual la almacenaremos, para efectos de nuestro ejemplo vamos a usar cadenas mágicas en el código y no archivos de configuración, dado que esto no es relevante para el ejercicio:

private const string Cadena = "Initial Catalog=NORTHWND;Data Source=TAVOPC;Integrated Security=SSPI;";

Escenario de una consulta simple a una sola tabla

Ahora vamos a codificar nuestro primer escenario, en el cual vamos a consultar en la tabla Ordenes, a través de Dapper y vamos a mapear el resultado a la entidad Orden (entidad creada por nosotros)

private static void ConsultarOrdenesDapper()
{
    using (IDbConnection db = new SqlConnection(Cadena))
    {
        var consulta = @"SELECT [OrderID] AS Id, [CustomerID] AS IdCliente, [EmployeeID] AS IdEmpledo,
                    [OrderDate] AS Fecha, [RequiredDate] AS FechaRequerida, [ShipCountry] AS Pais, [ShipCity] AS Ciudad
                    FROM [NORTHWND].[dbo].[Orders]";
 
        var stopwatch = new Stopwatch();
        stopwatch.Start();
 
        // Se ejecuta la consulta.
        var ordenes = db.Query<Orden>(consulta);
 
        stopwatch.Stop();
        System.Console.WriteLine("Dapper.Net: {0} registros obtenidos en {1} milisegundos.", ordenes.Count(),
          stopwatch.ElapsedMilliseconds);
    }
}

Como podemos ver es bastante sencillo usar Dapper, en este caso a través de la clase SqlConnection establecemos la conexión con la base de datos, y ejecutamos el método Query, especificando el tipo en el que queremos obtener el resultado de la consulta, cabe mencionar que el método Query no se encuentra en la clase SqlConnection por defecto, este es un método de extensión agregado por el Nuget de Dapper. Ahora invocaremos el método ConsultarOrdenesDapper desde el método Main de la clase program, y ejecutamos el programa para ver los resultados.


Como podemos apreciar obtenemos un resultado bastante óptimo de 856 registros en 4 milisegundos, ahora en cuánto tiempo resolverá EntityFramework esta consulta? pues vamos a averiguarlo.

Para crear nuestro modelo conceptual a través de EntityFramework, vamos a usar el enfoque "Code First From DataBase" el cual permite usar CodeFirst con una base de datos existente y crea el contexto y las entidades a partir de ella, observa aquí un tutorial detallado acerca de cómo usar este enfoque: CodeFirst From DataBase

Ahora que ya tenemos nuestro contexto vamos a codificar la misma consulta que realizamos con Dapper, pero esta vez la ejecutaremos a través de EntityFramework.

private static void ConsultarOrdenesEf()
{
    using (var contexto = new NorthwndModel())
    {
      var stopwatch = new Stopwatch();
      stopwatch.Start();
 
      var ordenes = contexto.Orders.ToList();
 
      stopwatch.Stop();
      System.Console.WriteLine("EntityFramework: {0} registros obtenidos en {1} milisegundos.", ordenes.Count,
      stopwatch.ElapsedMilliseconds);
    }
}

Ahora de igual forma vamos a invocar el método ConsultarOrdenesEf desde el método main de la clase Program, y ejecutamos de nuevo la aplicación para ver el resultado:


Pues la diferencia es bastante grande de 6 milisegundos de Dapper a 95 milisegundos de EntityFramework, sin lugar a dudas es una diferencia significativa, si bien 95 milisegundos siguen siendo poco esos milisegundos van sumando en cada transacción, y en una aplicación de alta demanda por ejemplo sí que se notarían y afectarían muy negativamente el rendimiento.

Ahora que hemos realizado este primer escenario comparativo podemos concluir que definitivamente el rendimiento de Dapper es muy superior al de EntityFramework, dado que como había mencionado antes el MicroOrm es muy rápido y liviano, por el contrario el Orm es bastante robusto y ofrece muchas más extensiones y funcionalidades que penalizan un poco el rendimiento. Sin embargo si analizamos y comparamos detenidamente el código de cada una de las implementaciones podemos decir que la implementación de EntityFramework es mucho más limpia, trazable y mantenible, otro aspecto muy importante en nuestras aplicaciones. Adicional vale la pena considerar el escenario en el cual trabajamos con tablas relacionadas, escenario que encontraremos en todas nuestras aplicaciones y que veremos a continuación.

Escenario de consulta a dos tablas relacionadas

Sin duda una de esas características que brilla por su ausencia en los MicroOrm con respecto a los Orm, es el manejo de relaciones entre entidades de una forma sencilla y objetual, obviamente el Micro Orm no tiene esto entre sus prioridades, pero si que hace falta. Para plantear este escenario vamos a realizar una consulta en la tabla ordenes y en la tabla ordenes detalle, en un escenario Eaguer, es decir donde necesitamos obtener la información en una sola consulta a la base de datos y no por demanda, vemos como sería la implementación con Dapper:

private static void ConsultarOrdenesDetallesDapper()
{
            var consulta = @"SELECT a.[OrderID] AS Id
	                    ,a.[CustomerID] AS IdCliente
	                    ,a.[OrderDate] AS Fecha
                          ,b.[ProductID] AS IdProducto
                          ,b.[UnitPrice] AS Precio
                          ,b.[Quantity] AS Cantidad
                          ,b.[Discount] AS Descuento
                      FROM [NORTHWND].[dbo].[Order Details] b
                      INNER JOIN [NORTHWND].[dbo].[Orders] a
                      ON a.OrderID = b.OrderID;";
 
            using (IDbConnection db = new SqlConnection(Cadena))
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();
 
                // Se ejecuta la consulta.
                var ordenesDetalle = db.Query<DetalleOrden>(consulta);
 
                stopwatch.Stop();
                System.Console.WriteLine("Dapper.Net: {0} registros obtenidos en {1} milisegundos.",
                    ordenesDetalle.Count(), stopwatch.ElapsedMilliseconds);
            }
}

De la implementación anterior podemos observar que se hace una consulta involucrando las dos tablas y se traen todos los registros de ambas, es decir se repiten los registros de la tabla ordenes por cada registro asociado en la tabla ordenesDetalle, y debido a esto se creó la entidad DetalleOrden, lo cual es una implementación que no nos permite orientar correctamente a objetos, ya que deberíamos tener la entidad orden y la entidad detalle separadas y cargarlas con la data, esto se debe a que el MicroOrm no permite manejar las relaciones y esta es una solución al escenario que planteamos de carga total. Ahora veamos como logramos la misma implementación pero usando EntityFramework.

private static void ConsultarOrdenesDetallesEf()
{
      using (var contexto = new NorthwndModel())
      {
         var stopwatch = new Stopwatch();
         stopwatch.Start();
 
         var ordenesDetalle = contexto.Orders.Include("Order_Details").ToList();
 
         stopwatch.Stop();
         .Console.WriteLine("EntityFramework: {0} registros obtenidos en {1} milisegundos.",
         ordenesDetalle.Count, stopwatch.ElapsedMilliseconds);
      }
}

De nuevo podemos observar a simple vista que la implementación con EntityFramework es mucho más limpia y orientada a objetos, hacemos una consulta sobre la tabla Ordenes y especificamos que se incluyan los datos de la tabla relacionada o propiedad de navegación Order_Details, de esta forma se obtienen los registros:


Todos los datos en sus respectivas entidades de una forma objetual, ahora veamos el rendimiento de cada de una de las implementaciones:


Sigue existiendo una diferencia abismal en el rendimiento de las consultas, y ahora que EntityFramework está gestionando las relaciones ha aumentado sustancialmente, dado que debe mapear las entidades y cada registro de las entidades de una forma anidada.

Escenario de inserción en una sola tabla

Ahora vamos a ver un par de escenarios en los cuales no consultaremos información si no que la guardaremos, para observar cómo se comportan tanto el MicroOrm como el Orm, veamos la implementación para Dapper y para EntityFramework:

private static void InsertarOrdenDapper()
{
    var consulta =
                $@"INSERT INTO [NORTHWND].[dbo].[Orders] (CustomerID, OrderDate) 
                    VALUES ('VINET', '{DateTime.Now.ToString("yyyy-MM-dd")}');";
    using (IDbConnection db = new SqlConnection(Cadena))
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
 
        // Se ejecuta la instrucción.
        db.Execute(new CommandDefinition(consulta));
 
        stopwatch.Stop();
        System.Console.WriteLine("Dapper.Net: un registro insertado en {0} milisegundos.",
        stopwatch.ElapsedMilliseconds);
    }
}

private static void InsertarOrdenEf()
{
    using (var contexto = new NorthwndModel())
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
 
        var orden = new Order
        {
            CustomerID = "VINET",
            OrderDate = DateTime.Now
        };
 
        contexto.Orders.Add(orden);
        contexto.SaveChanges();
 
        stopwatch.Stop();
        System.Console.WriteLine("EntityFramework: un registro insertado en {0} milisegundos.",
                    stopwatch.ElapsedMilliseconds);
    }
}

Como podemos ver dos implementaciones muy sencillas en Dapper y en EntityFramework para insertar un registro, ahora comparemos el rendimiento de ambas implementaciones:


En este escenario de inserción de un solo registro nos damos cuenta que en este aspecto la diferencia de rendimiento entre Dapper y EntityFramework no es tan grande, solo 7 milisegundos una diferencia en tiempo realmente pequeña.

Escenario de inserción en dos tablas relacionadas

Para terminar la comparación entre Dapper y EntityFramework vamos a ver el último escenario en el cual vamos a insertar información en dos tablas relacionadas, veamos entonces como es el código a implementar para cada tecnología:

private static void InsertarOrdenDetalleDapper()
{
      var consulta =
        $@"INSERT INTO [NORTHWND].[dbo].[Orders] (CustomerID, OrderDate) 
        VALUES ('VINET', '{DateTime.Now.ToString("yyyy-MM-dd")}') select SCOPE_IDENTITY();";
      using (IDbConnection db = new SqlConnection(Cadena))
      {
          var stopwatch = new Stopwatch();
          stopwatch.Start();
 
          // Se almacena la orden y se obtiene su Id Identity.
          var idOrden = (int)db.Query<decimal>(consulta).First();
 
          consulta = $@"INSERT INTO [NORTHWND].[dbo].[Order Details] 
          VALUES ({idOrden}, 41, 20, 100, 0);";
          db.Execute(new CommandDefinition(consulta));
 
          stopwatch.Stop();
          System.Console.WriteLine("Dapper.Net: registros relacionados insertados en {0} milisegundos.",
          stopwatch.ElapsedMilliseconds);
      }
}

private static void InsertarOrdenDetalleEf()
{
    using (var contexto = new NorthwndModel())
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
 
        var orden = new Order
        {
            CustomerID = "VINET",
            OrderDate = DateTime.Now,
            Order_Details =
            {
                new Order_Detail
                {
                    ProductID = 41,
                    UnitPrice = 20,
                    Quantity = 100,
                    Discount = 0
                }
            }
        };
 
        contexto.Orders.Add(orden);
        contexto.SaveChanges();
 
        stopwatch.Stop();
        System.Console.WriteLine("EntityFramework: registros relacionados insertados en {0} milisegundos.",
        stopwatch.ElapsedMilliseconds);
    }
}

Como podemos observar en este último escenario para EntityFramework creamos un solo objeto, especificando la información para la entidad padre y también para para la propiedad de navegación y EntityFramework se encarga de ejecutar las dos instrucciones de inserción, por el contrario con Dapper se debe ejecutar en primera instancia la instrucción para la tabla padre y obtener su Id, para posteriormente ejecutar la instrucción de la tabla relacionada, ahora observemos el desempeño de ambas implementaciones:


Como en el escenario anterior vemos que la diferencia no es muy significativa, cuando se trata de operaciones de inserción. Dados los anteriores escenarios podríamos concluir que Dapper tiene un rendimiento muy superior a EntityFramework en cuanto a consulta de datos se refiere, sin embargo en operaciones de inserción tienen un rendimiento muy similar. También podemos concluir que usando un Orm podemos lograr implementaciones mucho más limpias y objetuales y un código más mantenible.

En resumidas cuentas podemos concluir que los Micro Orm nos permiten practicidad, simplicidad y óptimo rendimiento, sacrificando un poco la mantenibilidad y orientación a objetos, mientras que los Orm nos permiten mejor mantenibilidad y orden sacrificando un poco el rendimiento, elegir uno u otro siempre dependerá del escenario que estemos resolviendo y según lo requieran nuestro atributos de calidad, recordemos que en el desarrollo de software no existen las balas de plata, y ambas tecnologías pueden ser muy válidas en determinados escenarios.

Y bueno amigos con esto damos por terminado el artículo, espero que esta comparación entre Dapper y EntityFramework les haya resultado interesante y de utilidad.

El código fuente lo puedes descargar de mi repositorio en GitHub.



No olvides visitar mi página en Facebook para mantenerte actualizado de lo que pasa en el Tavo.Net https://www.facebook.com/eltavo.net

Saludos, y buena suerte!

miércoles, 26 de noviembre de 2014

[EntityFramework] Usando EntityFramewok y sql Azure

Hola amigos, tuve el gusto de ser invitado a participar con un par de vídeos para la campaña #100DevDays de Microsoft Visual Estudio, realizada en el Channel9 Latam, en esta ocasión expliqué como usar EntityFramework y Sql Azure, aquí les dejo el vídeo y también puedes observar el paso a paso en este artículo: EntityFramework y Sql Azure

viernes, 14 de noviembre de 2014

[EntityFramework] Logueando e interceptando operaciones

Hola amigos, tuve el gusto de ser invitado a participar con un par de vídeos para la campaña #100DevDays de Microsoft Visual Estudio, realizada en el Channel9 Latam, en esta ocasión expliqué un poco acerca de intercepción de operaciones en EntityFramework, aquí les dejo el vídeo:

miércoles, 13 de agosto de 2014

[Patrones] Implementando patrón repositorio - Repository pattern en C# Parte II

En el artículo anterior conocimos y explicamos el patrón repositorio, vimos su propósito, su estructura, algunos casos comunes de uso, adicional creamos la estructura base en una solución de visual estudio, la cual seguiremos desarrollando a lo largo de este artículo y nos centraremos en la implementación de nuestros repositorios, recordemos que vamos a tener un repo para SqlServer, otro para MongoDB y otro para un Api "externa". Recordemos como va hasta el momento nuestra solución y nos enfocaremos en la parte señalada en rojo:


Para iniciar en el proyecto de Contrato vamos a crear las interfaces para cada repositorio, que definirán el contrato a implementar por los repositorios que vamos a crear o nuevos repos que puedan surgir en el futuro y que usen nuestras entidades de dominio Empleado, Artículo y DatosContacto, veamos entonces como quedan dichas interfaces:

    public interface IEmpleadoRepository
    {
        List<Empleado> ObtenerEmpleados();
 
        Empleado ObtenEmpleadoPoId(string id);
 
        void GuardarEmpleado(Empleado empleado);
    }

    public interface IArticuloRepository
    {
        List<Articulo> ObtenerArticulos();
 
        Articulo ObtenArticuloPorId(string id);
 
        ICollection<Articulo> ObtenerArticulosPorIdEmpleado(string idEmpleado);
 
        void GuardarArticulo(Articulo articulo);
    }

    public interface IDatosContactoRepository
    {
        DatosContacto ObtenerDatosContactoEmpleado(string idEmpleado);
    }

Ahora procedemos a crear el repositorio para SqlServer, para esto agregamos la siguiente estructura en el proyecto SqlRepository:


Como podemos ver tenemos una clase llamada Contexto, la que representará nuestro contexto de Entity Framework para interactuar con nuestra base de datos en Sql Server, en esta ocasión usaremos el enfoque de EF llamado Code First, si quieres profundizar más sobre este tema, te invito a leer esta serie de post relacionados. Adicional en la raíz del proyecto también tenemos una clase llamada BaseRepository, la cual contiene todas las operaciones básicas que pueden aplicar para cualquier entidad que se tenga que interactúe con la base de datos. Vamos a ver el código de estas dos clases que menciono:

    public partial class Contexto : DbContext
    {
        public Contexto()
            : base("name=Contexto")
        {
        }
 
        public virtual DbSet<Empleado.Empleado> Empleados { getset; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Empleado.Empleado>()
                .Property(e => e.Id)
                .IsUnicode(false);
 
            modelBuilder.Entity<Empleado.Empleado>()
                .Property(e => e.Nombre)
                .IsUnicode(false);
 
            modelBuilder.Entity<Empleado.Empleado>()
                .Property(e => e.Telefono)
                .IsUnicode(false);
        }
    }

Tenemos el mapeo a la base de datos de la tabla Empleados, y tenemos algunas configuraciones a través de Fluent Api para esta.

    public class BaseRepository<T> where T : class
    {
        protected DbContext Contexto = new Contexto();
        protected DbSet<T> DbSet;
 
        public BaseRepository()
        {
            DbSet = Contexto.Set<T>();
        }
 
        public void Insertar(T entidad)
        {
            DbSet.Add(entidad);
        }
 
        public void Eliminar(T entidad)
        {
            DbSet.Remove(entidad);
        }
 
        public IQueryable<T> Filtrar(Expression<Func<T, bool>> expresion)
        {
            return DbSet.Where(expresion);
        }
 
        public T ObtenerPorId(string id)
        {
            return DbSet.Find(id);
        }
 
        public IQueryable<T> ObtenerTodos()
        {
            return DbSet;
        }
 
        public void GuardarCambios()
        {
            Contexto.SaveChanges();
        }
    }

Como mencioné antes nuestro repositorio base para Sql Server, nos permite usarlo con cualquier entidad de Code First y realizar algunas operaciones básicas como obtener todos los registros, obtener filtrando por id, realizar una consulta filtrada, insertar y eliminar.

Ahora vamos a observar las entidades que tenemos al interior de la carpeta Empleado, que son Empleado y EmpladoRepository. La clase empleado se encarga de mapear la tabla Empleados de la base de datos y EmpleadoRepository es el repositorio específico para realizar operaciones con la tabla Empleados y hereda de nuestro repositorio base para implementar las operaciones que este expone.

    [Table("Empleados")]
    public partial class Empleado
    {
        [StringLength(50)]
        public string Id { getset; }
 
        [Required]
        [StringLength(50)]
        public string Nombre { getset; }
 
        [StringLength(10)]
        public string Telefono { getset; }
 
        [StringLength(50)]
        public string Direccion { getset; }
    }

Tenemos el mapeo de la tabla Empleados en nuestra base de datos y su configuración a través de Data Anottations.

    public class EmpleadoRepository : BaseRepository<Empleado>IEmpleadoRepository
    {
        public List<Dominio.Empleado> ObtenerEmpleados()
        {
            AutoMapper.Mapper.CreateMap<Empleado, Dominio.Empleado>();
            return
                new List<Dominio.Empleado>(ObtenerTodos().AsEnumerable().Select(AutoMapper.Mapper.Map<Dominio.Empleado>
                    )).ToList();
        }
 
        public Dominio.Empleado ObtenEmpleadoPoId(string id)
        {
            var empleado = ObtenerPorId(id);
 
            AutoMapper.Mapper.CreateMap<Empleado, Dominio.Empleado>();
            return AutoMapper.Mapper.Map<Dominio.Empleado>(empleado);
        }
 
        public void GuardarEmpleado(Dominio.Empleado empleado)
        {
            AutoMapper.Mapper.CreateMap<Dominio.EmpleadoEmpleado>();
            var emple = AutoMapper.Mapper.Map<Empleado>(empleado);
 
            Insertar(emple);
        }
    }

Como podemos ver, el EmpleadoRepository hereda de BaseRepository usando la entidad Empleado para realizar las operaciones, adicional implementa la interfaz IEmpleadoRepository, que define el contrato a implementar para este repositorio. En este repositorio tenemos tres métodos, ObtenerEmpelados(), ObtenerEmpleadoPorId() y GuardarEmpleado() los cuales usan métodos del repositorio base respectivamente.

Por último algo curioso en este repositorio es el uso del AutoMapper, que es una herramienta que nos permite mapear dos objetos que pueden tener una estructura diferente pero contener todos o algunos datos iguales. En este caso lo usamos para mapear la entidad Empleados de CodeFirst a nuestra entidad de domino Empleado, que recordemos se encuentra en el proyecto de dominio, y es la entidad devuelta por el repositorio y usada por los clientes que consuman el repo, esto con el fin de que todos los clientes "hablen" en términos del domino y todo quede centralizado en estas entidades. Si quieres profundizar más acerca del tema AutoMapper puedes observar este artículo del crack JulitoGTU.

Ahora ya tenemos listo el repositorio para interactuar con la base de datos Sql Server, es decir tenemos centralizada toda la lógica de acceso a datos en el repo, ahora podríamos consumir el repo a través de algún cliente (Aplicación web, escritorio, consola, etc.) para interactuar con la base de datos y estos no sabrían sobre la proveniencia de los datos.

Y bueno eso es todo por este artículo, en el cual implementamos el contrato de los repositorios y el repositorio especifico para acceso a datos de Sql Server usando Entity Framework Code First, en el próximo artículo terminaremos los repositorios, implementando el repo para acceso a datos en MongoDB y también para obtener información del servicio web api. Espero sea de utilidad y de interés para ustedes.

Continua en: Implementando patrón repositorio - Repository pattern en C# Parte III

Este ejemplo lo puedes descargar de mi repositorio en GitHub

No olvides visitar mi página en Facebook para mantenerte actualizado de lo que pasa en el Tavo.Net https://www.facebook.com/eltavo.net
Saludos, y buena suerte!

martes, 8 de abril de 2014

[EntityFramework] Nueva funcionalidad Code First, Update Visual Studio 2013 2 RC

Hola amigos, como todos sabemos recientemente se presentó el Microsoft Build 2014, en el cual entre otras cosas se presentaron grandes avances en las diversas tecnologías Microsoft, cómo por ejemplo Windows 8.1, Windows Phone 8.1, Microsoft Azure, Visual Studio, etc. Y entre las actualizaciones para Visual Studio 2013 encontramos algo bastante interesante en cuento a Entity Framework se refiere, y es el hecho de poder trabajar con el enfoque Code First teniendo en primera instancia nuestra base de datos, y lo mejor de esto, sin tener que usar los power tools que solemos usar para lograr esto, entonces a través de esta nueva funcionalidad de VS podemos crear en primera instancia nuestra base de datos y posteriormente podemos generar nuestro modelo Code First a partir de ella, bastante bueno para los que preferimos este enfoque de EF, ya que ahora podemos crear y modelar nuestra BD como estamos acostumbrados y luego vamos a tener todo el dominio de nuestro modelo conceptual como preferimos, y todo esto soportado nativamente por  nuestro invaluable IDE Visual Studio.

Pero bueno veamos en acción esta nueva actualización, y lo primero que les recomiendo es descargar el Update Visual Studio 2013 2 RC y una vez lo tengan instalado podrán observar esta nueva opción de la que estamos hablando.

Ahora para iniciar vamos a crear un nuevo proyecto de tipo librería de clases, como se muestra a continuación:


Una vez creada nuestra librería de clases, vamos a hacer clic derecho sobre ella y vamos a elegir la opción "Agregar nuevo ítem", y vamos a elegir el tipo de ítem "ADO.NET Entity Data Model":


Ahora viene la novedad, veremos que tenemos habilitada la nueva opción "Code First From Data Base" la cual seleccionaremos para ver que viene a continuación:


Lo que viene a continuación es similar a lo que estamos acostumbrados cuando usamos el enfoque Data Base First, es decir generar una conexión a la base de datos y seleccionar los elementos de esta a mapear:



Todo muy sencillo como es de costumbre. Y por último si finalizamos el asistente y esperamos algunos segundos veremos que se generaran todas nuestras clases POCO y obviamente nuestro contexto usando Code First y usando una combinación de Data Anottations y Fluent Api para configurar nuestras entidades.

Bueno amigos eso es todo de este acercamiento a esta actualización recientemente liberada para Entity Framewor Code First, espero les sea de utilidad y de interés.

Saludos, y buena suerte!

domingo, 30 de marzo de 2014

[EntityFramework] Resumen Code First

Hola amigos, les comparto el resumen de todo lo que aprendimos en esta serie de artículos acerca de Entity Framework Code 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 conceptos básicos y a tener en cuenta sobre Entity Framework Code First.

  • Aprendimos a crear nuestro modelo conceptual a través de clases POCO y luego vimos cómo crear nuestra base de datos basados en nuestras clases.

  • Aprendimos a configurar nuestras entidades para definir ciertas características de base de datos a través de atributos o Data Anottations.

  • Aprendimos a configurar nuestras entidades para definir ciertas características de base de datos a través de Fluent Api.

  • Aprendimos a configurar una relación de uno a uno entre nuestras entidades.

  • Aprendimos a configurar una relación de uno a muchos entre nuestras entidades.

  • Aprendimos a configurar una relación de muchos a muchos entre nuestras entidades.
  • Aprendimos a usar migraciones para actualizar los cambios de nuestro modelo a nuestra base de datos, además aprendimos a inicializar nuestra base de datos con datos de configuración.
  • Aprendimos a usar la herramienta de Power Tools para Entity Framework en Visual Studio, en especial para Code First.
Saludos y buena suerte!

viernes, 28 de marzo de 2014

[EntityFramework] Power Tools

Hola amigos, para terminar con esta serie de post acerca de Entity Framework Code First les quiero compartir una herramienta llamada Entity Framework Power Tools, que no es más que una extensión para visual estudio, la cual pueden encontrar en el siguiente sitio:

Entity Framework Power Tools

O también la pueden descargar a través del administrador de extensiones de su Visual Studio. Esta es una extensión bastante útil a la hora de elegir trabajar con Code first. Por ejemplo puede ser bastante engorroso crear por primera vez nuestra base de datos basado en nuestras entidades, ya que nos podemos equivocar en muchas cosas y se nos pueden pasar muchos detalles, pues bueno a través de este power tool podemos ver cómo va a quedar nuestro modelo antes de generar la base de datos para validarlo.

Adicional otra característica que en mi opinión es bastante útil es la herramienta de ingeniería inversa, que nos permite generar las clases POCO para una base de datos ya existente, esto para las personas que prefieran solo trabajar con Code First y no con otro enfoque de Entity Framework, en caso tal que tengan ya creada su base de datos podrán generar las entidades a partir de esta.

Adicional esta herramienta tiene otras características, las cuales pueden observar en el link que mencioné anteriormente, en mi opinión las dos características mencionadas son las más útiles.

Bueno amigos eso es todo, espero les sea de utilidad esta herramienta en sus proyectos, con esto damos por terminado nuestro tutotial acerca Entity Framework code First.

Saludos y buena suerte!

martes, 18 de marzo de 2014

[EntityFramework] Usando migraciones para actualizar cambios en nuestro modelo en Code First

En esta serie de artículos sobre Entity Framework Code First hemos visto diversos temas, desde creación y configuración inicial, hasta trabajo con las entidades. Y ahora que vamos en este punto surge la necesidad y la interrogante, de cómo podemos actualizar nuestra base de datos cuando surgen cambios en nuestras entidades. Pues bueno en este post vamos a ver cómo lo podemos hacer.

En primera instancia quiero mencionar que hay varios tipos de inicialización de base de datos en Entity Framework Code First, los cuales explico a continuación:

CreateDatabaseIfNotExists: Es el tipo de inicialización establecido por defecto, y solo crea la base de datos si esta no existe, es decir la primer vez que ejecutemos la inicialización a no ser que eliminemos la base de datos y volvamos a ejecutar, hay que tener en cuenta que si trabajamos con esta inicialización y cambiamos nuestro modelo obtendremos un error.

DropCreateDatabaseIfModelChanges:  Este tipo de inicialización elimina la base de datos existente y la crea de nuevo con las actualizaciones, siempre y cuando existan cambios en nuestro modelo de clases, la desventaja con esto es que tendremos perdida de datos.

DropCreateDatabaseAlways: Este tipo de inicialización elimina la base de datos existente y la crea de nuevo sin importar si hay nuevos cambios en el modelo o no. esto siempre conllevara perdida de datos y problemas de rendimiento al siempre tener que crear la base de datos.

Custom DB Initializer: Adicional podemos crear nuestro propio inicializador de base de datos si necesitamos algo muy específico, otro tipo de configuraciones, o ejecutar otro proceso externo para la inicialización, para esto podemos crear una clase que herede de una clase de inicialización cómo por ejemplo MigrateDatabaseToLatestVersion u otro de los mencionados.

MigrateDatabaseToLatestVersion: Nos permite actualizar automáticamente la base de datos, una vez inicie la aplicación, las actualizaciones pendientes se reflejaran en nuestra base de datos, este tipo de inicialización nos permite conservar los datos obviamente si no se trata de una instrucción Drop o Delete por ejemplo. Con este tipo es que podremos implementar migraciones en nuestra aplicación, por esto es importante conocer los diferentes tipos de inicialización que nos ofrece Entity Framework Code Fist.

Ahora sí, vamos a ver cómo implementar migraciones en nuestra base de datos.

Lo primero que debemos hacer es habilitar las migraciones, esto lo podemos hacer a través de la consola de paquetes nuget, de la siguiente forma:

En la barra de menús de Visual Studio seleccionamos Herramientas / Administrador de paquetes / Consola de administrador de paquetes y en esta consola seleccionamos en proyecto por defecto nuestro proyecto de acceso a datos donde tenemos nuestro modelo y escribimos lo siguiente:

enable-migrations -EnableAutomaticMigrations:$true

De esta forma se habilitan las migraciones en nuestro proyecto nos damos cuenta si leemos todo el log que se genera en la consola, ahora vamos a configurar nuestro contexto para sopórtalas.

Ahora si vamos al explorador de soluciones, veremos que se ha creado una carpeta llamada Migrations la cual contiene una clase llamada Configuration.cs.

Si exploramos la clase Configuration veremos que en su constructor el atributo AutomaticMigrationsEnabled se encuentra establecido en true, tal cual se lo indicamos en la consola de Nuget al ejecutar el comando, adicional veremos que hay un método sobre escrito llamado Seed, el cual nos permite cargar datos iniciales en nuestra base de datos, por ejemplo para cargar datos de configuración que se requieran desde el inicio para su correcto funcionamiento o para cargar tablas maestras de nuestra base de datos.

    internal sealed class Configuration : DbMigrationsConfiguration<EF6CodeFirst.Dominio.Context>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
 
        protected override void Seed(EF6CodeFirst.Dominio.Context context)
        {
            context.Productos.AddOrUpdate(
                p => p.Codigo,
                new Producto { Codigo = 1, Nombre = "Leche1", Descripcion = "Producto Lacteo" },
                 new Producto { Codigo = 2, Nombre = "Queso1", Descripcion = "Producto Lacteo" }
            );
        }
    }

Cómo vemos en el método Seed, creamos dos producto los cuales necesitamos crear al inicio para nuestro proyecto, adicional podemos ver que el constructor de la clase agregar el atributo AutomaticMigrationDataLossAllowed y lo establecimos en true, esto para asegurarnos que no suceda un error cuando posiblemente se pueda perder información tras una actualización, por ejemplo si decidimos eliminar un campo de alguna tabla tras la actualización nos diría que no se puede actualizar ya que se perdería la información que hay en ese campo, para esto habilitamos este atributo.

Para terminar con la configuración de las migraciones debemos indicar en el constructor de nuestro contexto que la estrategia de inicialización que vamos a usar es MigrateDatabaseToLatestVersion la cual explique anteriormente, y lo hacemos de la siguiente forma:

    public class Context : DbContext
    {
        public Context() : base("Productos")
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<ContextConfiguration>());            
        }
 
        public DbSet<Producto> Productos { getset; }
 
        public DbSet<Categoria> Categorias { getset; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // Aquí haremos nuestras configuraciones con Fluent API.
 
            modelBuilder.Configurations.Add(new ProductoMappings());
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.MapLeftKey("IdProducto"));
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.MapRightKey("IdCategoria"));
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.ToTable("ProductosCategorias"));
 
            base.OnModelCreating(modelBuilder);
        }
    }

Ahora podemos crear una app de consola para probar nuestro código y nos daremos cuenta que se creará la base de datos según nuestras configuraciones incluyendo los datos de carga inicial que establecimos en el método Seed, y por ultimo para probar las migraciones podemos eliminar una propiedad de alguna entidad de dominio y veremos que los cambios se ven reflejados en nuestra base de datos.

Y bueno amigos, eso es todo, espero les sea de utilidad y de interés este post acerca de migraciones en Entity Framework code First.

Saludos y buena suerte!

miércoles, 5 de marzo de 2014

[EntityFramework] Configurando una relación de muchos a muchos en Code First

En el artículo anterior vimos cómo configurar una relación de uno a muchos usando Data Annotations y Fluent Api, en esta ocasión vamos a ver cómo configurar una relación de muchos a muchos usando las mismas entidades de dominio Producto y Categoría.

Relación de muchos a muchos mediante Data Annotations:

Para lograr configurar una relación de muchos a muchos en Entity Framework Code First solo debemos agregar una propiedad de tipo colección en cada una de las entidades, obviamente dónde una referencia a la otra, entonces veamos cómo quedarán nuestras entidades Producto y Categoría:

    [Table("Productos")]
    public class Producto
    {
        public Producto()
        {
            Categorias = new HashSet<Categoria>();
        }
 
        [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; }
 
        public virtual ICollection<Categoria> Categorias { getset; }
    }

Cómo podemos ver agregamos la propiedad virtual de tipo ICollection Categoría, y en el constructor inicializamos dicha propiedad para evitar Null Reference Exception cuando agreguemos categorías al producto. Ahora hacemos lo mismo para la entidad Categoría:

    public class Categoria
    {
        public Categoria()
        {
            Productos = new HashSet<Producto>();
        }
 
        [Key]
        public int Id { getset; }
 
        [MaxLength(100)]
        public string Nombre { getset; }
 
        [MaxLength(200)]
        public string Descripcion { getset; }
 
        [Required]
        public virtual ICollection<Producto> Productos { getset; }
    }

Y listo ya con esto tenemos configurada nuestra relación de muchos a muchos entre las entidades Producto y Categoría, para probar vamos a crear una aplicación de consola y copiamos el siguiente código, obviamente con todo el contexto y demás que hemos creado en anteriores ejemplos:

    class Program
    {
        static void Main(string[] args)
        {
            var categoria = new Categoria { Id = 1, Nombre = "Lacteos", Descripcion = "Productos lacteos" };
            var categoria2 = new Categoria { Id = 1, Nombre = "carnes", Descripcion = "Productos carnicos" };
 
            var producto = new Producto { Codigo = 1, Nombre = "Leche", Descripcion = "Producto Lacteo" };
            var producto2 = new Producto { Codigo = 2, Nombre = "Queso", Descripcion = "Producto Lacteo" };
 
            producto.Categorias.Add(categoria);
            producto.Categorias.Add(categoria2);
 
            categoria.Productos.Add(producto);
            categoria.Productos.Add(producto2);
 
            using (var contexto = new Context())
            {
                contexto.Productos.Add(producto);
                contexto.Categorias.Add(categoria);
                contexto.SaveChanges();
            }
        }
    }

Y ahora podemos ver que se han creado las tablas Productos y Categorías, y adicional se creó la tabla ProductoCategorias para representar la relación de muchos a muchos:


Relación de muchos a muchos mediante Fluent Api:

Ahora vamos a configurar la relación de muchos 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<Producto> Productos { getset; }
 
        public DbSet<Categoria> Categorias { getset; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // Aquí haremos nuestras configuraciones con Fluent API.
 
            modelBuilder.Configurations.Add(new ProductoMappings());
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.MapLeftKey("IdProducto"));
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.MapRightKey("IdCategoria"));
 
            modelBuilder.Entity<Producto>().HasMany<Categoria>(c => c.Categorias).WithMany(e => e.Productos).Map(e =>
                e.ToTable("ProductosCategorias"));
 
            base.OnModelCreating(modelBuilder);
        }
    }

Por ultimo si borramos la base de datos anteriormente creada y volvemos a ejecutar el proyecto de consola, veremos que obtendremos los mismos resultados.

Y bueno amigos, eso es todo, espero les sea de utilidad y de interés este post acerca de relación de muchos a muchos en Entity Framework code First, en próximos artículos observaremos más acerca de inicializaciones y migraciones en Code First.

Saludos y buena suerte!