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

sábado, 23 de julio de 2016

Introducción a EntityFramework Core

Como todos sabemos desde el año anterior Microsoft anunció una nueva versión del .Net Framework, llamado .Net Core, una versión del framework mucho más liviana y modular, diseñada para ser multiplataforma. Uno de los productos desarrollados a la par fue EntityFramework Core, una nueva versión del ORM de Microsoft mucho más liviana la cual incluye muchas de las características implementadas en EntityFramework 6.x la última versión estable de este ORM.


El pasado 27 de Junio fue anunciada por Microsoft la liberación de la primera versión estable del .Net Core Framework o .Net Core 1.0 y consigo la liberación de Asp.Net Core 1.0 y EntityFramework Core 1.0 liberación bastante esperada por todos debido al inicio de un nuevo Framework mucho más modular y multiplataforma.

EntityFramework Core, es una versión multiplataforma, mucho más liviana y optimizada para la nube, en trabajo conjunto con Asp.Net Core, además de esto está pensado para realizar mapeos con múltiples motores de base de datos relaciones, así mismo como bases de datos no relacionales, como DocumentDB,  Azure Table Storage y Redis por ejemplo, si bien aún no tenemos estos providers en la versión actual de EF Core, se espera que sea incluida en futuras versiones.

Entre algunas de las características ya disponibles en EF Core tenemos las siguientes:
  • Fluent Api
  • DataAnnotations
  • RelationShips
  • Shadow State Properties
  • ChangeTraking
  • Optimistic Concurrency
  • Async SaveChanges
Y algunas características importantes que aún no están disponibles pero que están Backlog:
  • Lazy loading
  • Creating model from DataBase with Wizard
  • Update Model From DataBase
  • Stored Procedure Mapping
  • Connection Resiliency
Si quieres observar el listado completo de características implementadas y características por implementar en EF Core, te invito a que observes su RoadMap en la siguiente página: EF Core RoadMap.

Otro tema importante a tener en cuenta es los proveedores de base de datos que actualmente soporta EntityFramework Core, que se mencionan a continuación:
  • Microsoft Sql Server
  • SQLite
  • Postgres
  • Sql Server Compact edition
  • InMemory
  • DevArt has paid providers for MySQL, Oracle, and many other databases
Para terminar les recomiendo tener presente algunos Issues conocidos de EntityFramework Core, que aún no se han solucionado y se deben tener en cuenta, los cuales puedes encontrar en el siguiente link: EntityFramework Core Known Issues

Es una gran noticia la liberación de .Net Core, Asp.Net Core y por supuesto EntityFramework Core, sin embargo es importante tener en cuenta que son tecnologías creadas desde inicio y no una evolución de las versiones full, dado esto son tecnologías que están en proceso de maduración y aún no cuentan con muchas características, por esto es importante documentarnos a la hora de usarlos para proyectos empresariales o productivos, en próximos artículos de esta serie de EF Core observaremos nuevas características y cambios importantes con respecto a la versión 6x

Y bueno amigos con esto damos por terminado este artículo de introducción a EntityFramework Core, espero les haya resultado interesante y de utilidad.

No olvides darle me gusta 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!

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!

lunes, 29 de febrero de 2016

Creando un BackEnd con EntityFramework Core y Asp.Net Web Api


Como todos sabemos desde el año anterior Microsoft anunció una nueva versión del .Net Framework, llamado .Net Core, una versión del framework mucho más liviana y modular, diseñada para ser multiplataforma. Uno de los productos desarrollados a la par fue EntityFramework Core, una nueva versión del ORM de Microsoft mucho más liviana la cual incluye muchas de las características implementadas en EntityFramework 6.x la última versión estable de este ORM, ya que EF Core aún se encuentra en Pre-Release.


EntityFramework Core, es una versión mucho más liviana y optimizada para la nube, en trabajo conjunto con Asp.Net Core, además de esto está pensado para realizar mapeos con múltiples motores de base de datos relaciones, así mismo como bases de datos no relacionales, como DocumentDB por ejemplo, si bien aún no tenemos esta característica en la versión actual de EF Core, se espera que sea incluida en futuras versiones.

En la versión Pre-Release de EF Core encontramos características como el uso del enfoque CodeFirst, relaciones a través de propiedades de navegación, creación del modelo usando convenciones, Shadow properties, que es una nueva característica bien interesante y la cual veremos más adelante en este blog, Changes Traking, concurrencia optimista, transacciones relaciones, entre otras características con las cuales estamos familiarizados y esperamos de cualquier ORM que usemos.

Entre futuras características a implementar en EF Core tenemos el uso de los famosos DataAnnotations, Queries sobre las propiedades de navegación, estabilización de soporte para multiplataforma, auditoria de operaciones, conexión y mapeo para DocumentDB, entre otras características.

Ahora que conocemos un poco EntityFramework Core, vamos a observar un HOL o tutorial en el cual desarrollaremos un BackEnd que use EntityFramework Core como ORM además de las siguientes tecnologías:
  • Microsoft Azure Sql Db: Como base de datos relacional en la nube, para almacenar los datos
  • EntityFramework Core: Como ORM para persistencia y acceso a datos
  • Asp.Net Web Api: Como marco de trabajo para la creación de servicios Http
  • Telerik Fiddler: Como cliente para probar nuestros servicios
Ahora sí, manos a la obra, ingresa al siguiente link, en el cual encontrarás el paso a paso de como implentar el BackEnd.

Y puedes descargar los fuentes de la siguiente ruta: Fuentes


Espero este artículo sea de utilidad y 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!

lunes, 2 de junio de 2014

[EntityFramework] Agregando propiedades y metadatos a nuestras clases autogeneradas en DB First

Hola amigos, ya que estamos dando por terminada esta serie de post sobre Entity FrameWork no quería dejar a un lado una importante característica que debemos conocer cuando trabajamos con el enfoque Data Base First y que seguro vamos a necesitar en cualquier proyecto en el que usemos este enfoque, y quiero antes que nada plantearles una necesidad para que comprendan con mayor facilidad la utilidad del tema que vamos a tratar en este artículo:

"Recordemos que un principio que debemos tener presente como desarrolladores es, nunca debemos modificar código autogenerado puesto que una vez se vuelva a autogenerar por cualquier motivo, perderemos los cambios que hicimos en el archivo en cuestión"

Bueno, ahora teniendo clara esta premisa, por si aún no se habían topado con algún caso de este tipo, surgen un par de interrogantes cuando trabajamos con Entity Framework DataBase First y son las siguientes:
  1. ¿Cómo puedo yo entonces agregar propiedades a mi entidad de domino directamente que no necesariamente quiero que persistan a mi base de datos?
  2. ¿Cómo puedo yo agregar metadata (Atributtes Data Anottations) adicional a mis entidades de domino?
Pues bien, creo que con estas dos interrogantes ya nos queda claro cuál es la necesidad de usar clases parciales para extender nuestras entidades autogeneradas. Ahora veamos como lo podemos lograr.

En primera instancia vamos a crear un modelo de Entity Framework usando el enfoque DataBase First el cual podemos observar en detalle en este artículo:  Creando nuestro modelo conceptual con DataBase First y como es normal veremos que se autogeneran nuestras entidades con todos sus metadatos, a este código es el que me refiero, no se puede modificar!

En nuestro caso se generó la entidad producto, como vemos a continuación. Si leemos el comentario en el encabezado de la clase veremos que se advierte de las consecuencias de modificarla:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
namespace DataBaseFirstDemo.Dominio
{
    using System;
    using System.Collections.Generic;
    
    public partial class Producto
    {
        public Producto()
        {
            this.Categorias = new HashSet<Categoria>();
        }
    
        public string Nombre { getset; }
        public int Codigo { getset; }
    
        public virtual ICollection<Categoria> Categorias { getset; }
    }
}

Ahora bien, que tal si queremos agregar una nueva propiedad a la entidad en la cual podamos obtener el código y el nombre del producto en una sola cadena? para esto creamos una nueva clase parcial llamada producto, la cual debe tener el mismo NameSpace que la clase producto autogenerada, y cabe aclarar algo, el archivo .cs debe tener un nombre diferente a Producto.cs, pero la clase en su interior debe tener el nombre de Producto, para que el FrameWork las trate como una sola. Tal y como vemos a continuación:


Como podemos ver tenemos las dos clases que físicamente son diferentes, es decir en dos archivos diferentes pero lógicamente son una sola, ya que desde la clase que hemos creado podemos ver las propiedades Codigo y Nombre que fueron autogeneradas.

Bastante sencillo, ahora vamos a ver cómo podemos agregar metadata adicional a las propiedades autogeneradas. Ya que como sabemos Entity Framework genera la metadata que obtiene desde la base de datos, como la longitud del campo, constrains y demás.

Lo primero que debemos hacer es crear una clase que puede estar en el interior del archivo Producto.cs que creamos nosotros y la podemos llamar ProductoMetaData, en la cual vamos a replicar todas aquellas propiedades a las cuales queremos agregar metadata adicional, en nuestro caso vamos a replicar la propiedad Nombre, para especificar que es requerida y que solo debe permitir una longitud máxima de 4 caracteres:

using System.ComponentModel.DataAnnotations;
 
namespace DataBaseFirstDemo.Dominio
{
    [MetadataType(typeof(ProductoMetaData))]
    public partial class Producto
    {
        public string InformacionProducto
        {
            get
            {
                return string.Format("{0} - {1}"this.Codigo, this.Nombre);
            }
        }
    }
 
    public class ProductoMetaData
    {
        [RequiredMaxLength(4)]
        public string Nombre { getset; }
    }
}

Y para finalizar debemos indicar que esta clase de metadata va a ser usada por nuestras clase Producto, y lo hacemos decorando nuestras clase con el atributo MetadataType e indicando la clase de metadata que acabamos de crear, tal y como se ve en el fragmento de código anterior.

Bueno amigos eso es todo de esta muestra de cómo agregar propiedades y metadata adicional a nuestras entidades autogenradas en DataBase First, espero les sea de utilidad y de interés. Y no duden en compartirlo.

Saludos, y buena suerte!

miércoles, 14 de mayo de 2014

Entity Framework Tooling, herramientas para mejorar nuestra productividad!

Hola amigos, para ir terminando con esta serie de post sobre Entity Framework quiero recomendarles un par de herramientas que son bastante útiles para mejorar nuestra productividad y para hacer nuestra labor un poco más fácil. En un artículo anterior ya habíamos visto por ejemplo los Entity Framework Power Tools que nos ayuda bastante con el trabajo en el enfoque Code First, y también vimos que en el último build de Microsoft se presentó por llamarlo así un nuevo enfoque "Code Second" en el cual podemos Generar nuestras clases Poco como en Code first pero esta vez generándolas a partir de nuestra base de datos.

Entity Framework Profiler

Bueno entrando en materia la primer herramienta de la que les quiero hablar es de Entity Framework Profiler, que es una herramienta licenciada que nos permite observar en tiempo real las consultas sql o Transact Sql que genera Entity Framework para comunicarse con la base de datos, ya que como vimos en artículos anteriores EF genera estas sentencias a partir de nuestras consultas linq. Ahora veamos cómo se usa:

Lo primero que debemos hacer es descargar el .zip en el cual se encuentran dlls, ejecutable y demás archivos necesarios para el funcionamiento de la herramienta, de la siguiente url: http://www.hibernatingrhinos.com/products/efprof


Una vez tengamos el zip, debemos referenciar en nuestra aplicación la dll HibernatingRhinos.Profiler.Appender.dll y debemos escribir la siguiente instrucción en el evento en dónde inicia nuestra página, cómo en nuestro caso utilizaremos una aplicación de consola lo haremos en el método main de la siguiente forma:

        static void Main(string[] args)
        {
            HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler.Initialize();
            using (var prodcutosContext = new ProdcutosContext())
            {
                var productos = prodcutosContext.Productos;
                var p = productos.ToList();
            }
        }

De esta forma inicializamos el profiler para que haga depuración de las sentencias linq. Ahora solo debemos ejecutar la aplicación EFProf que se encuentra también en él .zip que descargamos, y debemos activar nuestra licencia trial o paga si la tenemos y veremos la siguiente pantalla:


Ahora solo debemos ejecutar nuestra aplicación con EFProf ejecutando y veremos una traza de todas las sentencias sql que Entity Framework ha creado por nosotros:


Genial, a través de esta herramienta podemos hacer múltiples análisis de nuestra consultas, para poder optimizarlas si es el caso, o encontrar problemas que se nos presenten, adicional podemos ver alertas con respecto a las consultas, la verdad es que es una herramienta sumamente útil. Solo les dejo un abre bocas de lo que es pero los invito a seguir investigando acerca de ella ya que aunque es paga se le puede sacar muy buen provecho. Una alternativa integrada ya con Visual Studio para ver las sentencias Sql ejecutadas puede ser observar el IntelliTrace de depuración el cual nos muestra las sentencias paso a paso:


Bueno y que tal si a través de alguna de estas dos herramientas descubrimos algún problema de rendimiento que deseemos mejorar en nuestras consultas o alguna posibilidad de mejora? y logramos optimizar la consulta como lo deseamos, ¿No sería muy útil poder convertir esta consulta Sql optimizada en una consulta Linq? a mi juicio si lo es, ya que llevamos la optimización al lenguaje de consulta utilizado por Entity Framework, y en esta labor nos puede ayudar la siguiente herramienta que les quiero mostrar: Linquer

Linquer

Linquer es una herramienta que nos permite convertir sentencias Transact Sql en instrucciones Linq, y que soporta los lenguajes c# y vb, bastante útil para aprender linq, si ya tienes dominio de Transact Sql, al igual que Entity Framework Profiler, tiene una versión de pago y otra trial, y la podemos descargar del siguiente link: http://www.sqltolinq.com/downloads

Una vez instalado podremos conectarnos a nuestro contexto a través de la herramienta para convertir de Sql a linq, como vemos a continuación:


Y para terminar quiero compartirles esta última herramienta:

LinqPad

LinqPad es una herramienta que nos permite realizar consultas Linq directamente contra nuestra base de datos, sin tener que ejecutar nuestra aplicación para ver qué resultados arrojará nuestra sentencia en tiempo de ejecución, a través de esta herramienta podemos escribir consultas linq en leguajes como c#, vb y f# además de poder escribir sentencias en Transact Sql. adicional podemos ver la sentencia Sql que genera la consulta linq que ejecutemos. Veamos un poco de cómo funciona:

Lo primero que debemos hacer es descargar e instalar la herramienta del siguiente link: https://www.linqpad.net/

Posteriormente podemos agregar nuestra conexión a la base de datos o a un contexto de EF directamente si lo deseamos:

Para esto especificamos una cadena de conexión:


Y enseguida veremos las tablas de nuestra base de datos, sobre la cual podemos ejecutar sentencias linq directamente, tal como se muestra a continuación:


Y adicional si seleccionamos la opción de resultados Sql, podremos ver la sentencia Transact Sql que generó esta consulta linq:


Muy útiles estas herramientas para mejorar nuestra productividad a la hora de trabajar con Entity Framework, que otras herramientas conoces?

Bueno amigos eso es todo de esta muestra de tooling o herramientas para facilitar nuestro trabajo en Entity Framework, espero les sea de utilidad y de interés. Y no duden en compartirlo.

Saludos, y buena suerte!