Haciendo fácil el acceso a datos con Entity Framework Core

Entity Framework Core

Segunda entrada en el blog y vengo a hablaros de otra situación que se dio en mi oficina… Otro compañero acaba de meterse en un proyecto de uso intensivo de bases de datos en el que requiere de una herramienta que le solucione la papeleta.

En mi día a día, he trabajado bastante con Entity Framework 6, el «clásico», pero hace algún tiempo encontré Entity Framework Core . Entity Framework Core partió con un set de herramientas bastante limitado, no habiendo comparación posible con su «hermano mayor» Entity Framework 6. Pese a todo, Entity Framework Core fue diseñado con la filosofía de la era «cloud«, y estaba super optimizado para las cosas que hacía. Todo esto ha cambiado con la versión 2.0, (os dejo un enlace con la comparación y set de utilidades).

En el momento actual, tenemos entre manos una herramienta que si bien no es tan madura como Entity Framework 6, si tiene un madurez a tener en cuenta. Un punto a favor muy fuerte que tiene, es su posibilidad de ejecución multiplataforma, lo cual, nos permite usarlo con .Net Framweork o con .Net Core (¡y eso a mi me encanta!).

Una vez dicho esto, vamos a meternos en faena… ¿Como resolvimos esto? Como es de suponer, ¡¡¡con Entity Framework Core!!!. En este caso, como se dispone del modelo de la base de datos, utilizamos la opción «Database First». Aunque también existe la opción «Code First», para que la base de datos se genere desde el código, y hablaremos de ella en otro post…

Modelo

Modelo DB

Para este caso, he creado un modelo como este:

En el tenemos 2 relaciones 1 a muchos:

  1. Un profesor podrá impartir varios cursos.
  2. Cada curso puede tener varios alumnos.

En este caso, utilizaré para el ejemplo una base de datos MySql, al ser una base de datos gratuita.

Teniendo claro el modelo, vamos al lío!

Creando la solución

Lo primero, sera crear un proyecto de consola en c# y .Net Framework (o .Net Core, lo que se prefiera):

consola .net full

Paquetes

Con el proyecto creado, vamos a descargar los paquetes de Entity Framework Core vía NuGet:

La imagen muestra el paquete Entity FRamework Core
La imagen muestra el paquete Entity FRamework Core Tools

En caso de querer hacerlo vía consola:

PM->Install-Package Microsoft.EntityFrameworkCore -Version 2.1.3
PM->Install-Package Microsoft.EntityFrameworkCore.Tools -Version 2.1.3

Solo falta descargar el proveedor de datos,en este caso MySql, y para eso, vamos a utilizar una implementación que va muy bien con Entity Framework Core:

La imagen muestra el paquete Pomelo para Entity Framework Core

O como siempre, por consola:

PM->Install-Package Pomelo.EntityFrameworkCore.MySql -Version 2.1.2

Generando el DbContext

Una vez que tenemos todo instalado, vamos a ejecutar la generación del contexto. Para eso, usaremos el comando «scaffold» en la Consola de Administrador de Paquetes (No, Entity Framework Core no dispone de interfaz. Pero no requiere más que de unos pocos comandos, vamos, que no va a ser muy duro).

PM->scaffold-dbcontext "Server=localhost;Database=postefcore;Uid=root;Pwd=root;" Pomelo.EntityFrameworkCore.Mysql -outputdir Models -context PostDbContext

Analicemos los argumentos:

  1. -dbcontext
  2. -outputdir
  3. -context

En «dbcontext» le estamos pasando el contexto que queremos utilizar. Utilizaremos una cadena de conexión y un proveedor Entity Framework Core para eso. En este caso Pomelo.EntityFrameworkCore.Mysql, si utilizáramos otro, tendríamos que indicarlo aquí.

En «outputdir» le indicamos la ruta en nuestro proyecto donde queremos que cree las clases necesarias para funcionar.

En «context» le indicamos el nombre que le queremos dar a nuestro contexto de datos.

Una vez termine la ejecución, veremos algo como esto en nuestro proyecto:

Contexto

En caso de que lo que queramos sea actualizar el modelo porque hemos hecho cambios en la db, lo haríamos con el siguiente comando:

PM->scaffold-dbcontext "Server=localhost;Database=postefcore;Uid=root;Pwd=root;" Pomelo.EntityFrameworkCore.Mysql -outputdir Models -context PostDbContext -force

En este caso, hemos añadido el argumento – force para que sobre escriba lo que hay.

Puedes leer más sobre los argumentos aquí.

Insertando datos

Con esto que hemos hecho, ya podemos acceder a la base de datos mediante el ORM, y operarla como necesitemos, por ejemplo, vamos a añadir 1 profesor, 2 cursos y 4 alumnos. Para ello, insertamos el siguiente código en nuestra clase program:

 
using (PostDbContext context = new PostDbContext())
{
    //Creamos el profesor
    Profesores profesor = new Profesores() {Nombre = "Pedro" };
    context.Add(profesor);
    //Creamos los cursos
    Cursos curso1 = new Cursos() { Nombre = "Matematicas", IdProfesor = profesor.IdProfesor };
    context.Add(curso1);
    Cursos curso2 = new Cursos() { Nombre = "Lenguaje", IdProfesor = profesor.IdProfesor };
    context.Add(curso2);
    //Creamos los alumnos
    Alumnos alumno1 = new Alumnos() { Nombre = "Jorge", IdCurso = curso1.IdCurso };
    context.Add(alumno1);
    Alumnos alumno2 = new Alumnos() { Nombre = "Juan", IdCurso = curso1.IdCurso };
    context.Add(alumno2);
    Alumnos alumno3 = new Alumnos() { Nombre = "Andrea", IdCurso = curso2.IdCurso };
    context.Add(alumno3);
    Alumnos alumno4 = new Alumnos() { Nombre = "Sandra", IdCurso = curso2.IdCurso };
    context.Add(alumno4);
    //Guardamos los cambios
    context.SaveChanges();
}

Pese a que las tablas requieren de IDs de las relaciones, y que la consulta no se ejecuta hasta llamar a SaveChanges(), Entity Framework Core es capaz de almacenar las relaciones y asignar los IDs correspondientes. Así evitamos tener que hacer una consulta para obtener el ID del profesor, antes de de añadírselo a un curso, o el id de un curso antes de añadírselo a un alumno. Esto es una gran ventaja, ya que evita la necesidad de una función, o de dos consultas a la base de datos. Por otro lado, cuando ejecutamos la llamada a SaveChanges(), Entity Framework Core rellena los datos de ids con los valores que se han asignado en la base de datos.

Leyendo datos

Ahora, vamos a leer datos aprovechando la navegación de propiedades. Con ella, vamos a obtener un profesor. Con el profesor,obtendremos todos sus alumnos sin necesidad de ejecutar varias consultas o un largo «inner join». Para eso, insertamos el siguiente código:

 
using (PostDbContext context = new PostDbContext())
{
    var profesor = context.Profesores //Indicamos la tabla
                          .Include(x => x.Cursos) //Incluimos los resultados coincidentes de la tabla cursos (inner join)
                          .ThenInclude(x => x.Alumnos) //Incluimos los resultados coincidentes de la tabla alumnos (inner join)
                          .First(); //Seleccionamos el primero
    foreach (var curso in profesor.Cursos)
      foreach (var alumno in curso.Alumnos)
        Console.WriteLine($"El alumno {alumno.Nombre} recibe el curso de {curso.Nombre},impartido por {profesor.Nombre}");
}

(Para que podamos utilizar .Include, hay que añadir el using correspondiente)

 
using Microsoft.EntityFrameworkCore;

Obteniendo por consola algo así:

El alumno Juan recibe el curso de Matematicas,impartido por Pedro
El alumno Jorge recibe el curso de Matematicas,impartido por Pedro
El alumno Sandra recibe el curso de Lenguaje,impartido por Pedro
El alumno Andrea recibe el curso de Lenguaje,impartido por Pedro

Lo cual vemos que coincide con los datos que hemos introducido, aportándonos así este ORM un nivel de abstracción que nos puede facilitar mucho la vida. Por no hablar de la posibilidad de realizar todo esto de manera asíncrona. Todo ello de manera transparente a nosotros, y sin ninguno esfuerzo adicional.

Cabe destacar, que aunque no lo he indicado expresamente, Entity Framework Core nos permite trabajar con las tablas de la base de datos mediante LinQ. De este modo,podemos trabajar con la base de datos sin necesidad de utilizar sentencias SQL, con una herramienta fuertemente tipada.

En el próximo post, hablaremos de la opción «Code First», y ahondaremos en las bondades que nos aporta utilizar un Entity Framework Core.

Generación de ficheros «Excel» (xlsx) con ClosedXML

closedxml

Después de llevar tiempo pensando en empezar a crear un blog, la semana pasada un compañero me pidió ayuda en un proyecto en el que necesitaban generar un excel en un servidor, el cual se enviaría al cliente, pero el servidor podía o no tener excel…

-Para para!! ¿y tu quien eres?
-Tienes razón, no me he presentado…

Antes de nada, me voy a presentar, yo soy Jorge, un apasionado de las tecnologías de Microsoft, en especial .Net y Net Core. Trabajo como ingeniero de software en una empresa especializada en soluciones industriales, y es este bagaje el que me lleva querer compartir esas cosillas que he ido aprendiendo.

Bueno, volviendo a la materia… Un compañero me pidió ayuda para generar un fichero «excel» sin necesidad de tener MS Excel, esto es algo que parece poco coherente, pero son muchas las situaciones en las que se necesita generar un documento de acceso público para programas que no necesariamente tenemos en nuestro servidor, ya sea por incompatibilidad o por ser propietarios. En este caso concreto, existe un SDK para poder hacer este trabajo, OpenXML. El principal problema de este SDK, es su pronunciada curva de aprendizaje, que hace que no sea rentable utilizarlo para usos puntuales…

Y ahí es donde entran implementaciones más ligeras como SpreadSheetLight o ClosedXML, siendo este ultimo del que vamos a utilizar hoy. Pero basta ya de hablar, y vamos a la carga!!

En primer lugar, crearemos un proyecto de consola de .Net Framweork:

Imagen planitllas

Lo siguiente que tenemos que hacer es añadir el paguete ClosedXML a traves de nuget. Esto se puede hacer a través de la «Consola de Administrador de Paquetes» con el comando:

«Install-Package ClosedXML -Version 0.93.1»

Otra opción, es utilizar el administrador que integra VS:

Teniendo ya instalado el paquete, en el propio program.cs, añadiremos el código básico del ejemplo de GitHub:

 
using ClosedXML.Excel;

namespace PostClosedXML
{
  class Program
  {
    static void Main(string[] args)
    {
      using (var workbook = new XLWorkbook())
      {
        var worksheet = workbook.Worksheets.Add("Sample Sheet");
        worksheet.Cell("A1").Value = "Hello World!";
        worksheet.Cell("A2").FormulaA1 = "=MID(A1, 7, 5)";
        workbook.SaveAs("HelloWorld.xlsx");
      }
    }
  }
}

Esto, generará un excel llamado «HelloWorld» junto al ejecutable de la aplicación, pero obviamente, esto es un ejemplo básico en el que se ven las bondades que tiene… Es posible cargar archivos .xlsx que ya existan, pasando la ruta en el constructor y así editarlo, por ejemplo,vamos a modificar el caso anterior para cargar un excel y añadir otra pestaña llamada FixedBuffer, que contenga el lo mismo pero en mayúsculas:

 
using ClosedXML.Excel;
using System.Linq;

namespace PostClosedXML
{
  class Program
  {
    static void Main(string[] args)
    {
      using (var workbook = new XLWorkbook("HelloWorld.xlsx"))
      {
        //Buscamos con LinQ la hohja que nos interesa copiar
        var SampleSheet = workbook.Worksheets.Where(x => x.Name == "Sample Sheet").First();
        //Añadimos una hoja nuevo
        var worksheet = workbook.Worksheets.Add("FixedBuffer");
        //Copiamos los valores
        worksheet.Cell("A1").Value = SampleSheet.Cell("A1").GetString().ToUpper();
        worksheet.Cell("A2").FormulaA1 = SampleSheet.Cell("A2").FormulaA1;
        //Guardamos el libro
        workbook.Save();
      }
    }
  }
}

Como se ve en el ejemplo anterior, podemos utilizar LinQ para movernos entre las hojas y celdas, lo cual nos facilita mucho el trabajo de acceder a zonas concretas de nuestro documento.

En futuros post, ampliaré la información sobre ClosedXML para dar estilo a celdas, generar tablas y demás.

Solo una cosa más… En este ejemplo, hemos utilizado .Net Framework, pero si echamos un vistazo rápido al repositorio de GitHub o a NuGet…

Sorpresa!!! Es compatible con .Net Standard!!!! 

¿Que quiere decir esto? Pues que podríamos utilizarlo en nuestra aplicación Net Core y ASP Net Core, puediento generar documentos xlsx en nuestro código ejecutado en cualquier plataforma (No solo en Windows)

En el este enlace puedes descargar el código del proyecto