Leer datos desde una hoja Excel con LinqToExcel

Leer datos desde una hoja Excel con LinqToExcel
Sin comentarios Facebook Twitter Flipboard E-mail

Una de las cosas más pesadas que nos podemos encontrar al desarrollar aplicaciones de gestión de datos es el interaccionar con las aplicaciones Office, y el uso de las librerías Interop.

Sin embargo la expansión de proyectos Open Source (y la inmensa mayoría de ellos gratuitos) que se distribuyen por el excelente gestor de Paquetes NuGet, me ha permitido acceder a una pequeña pero potente librería para leer ficheros Excel utilizando Linq: LinqToExcel.

Pre requisitos

El tutorial está elaborado en C#, para framework .NET 4.5, sobre Visual Studio 2013 Update 1 (cualquier versión gratuita Express es válida). Si no lo tuvieras lo puedes descargar e instalar desde aquí.

Lo siguiente es hacer un fichero excel sencillito (yo lo he hecho con Office 2013, pero en teoría lee cualquier fichero xslx) llamado GenbetaDevEjemplo.xslx en donde voy a añadir tres títulos de columna llamados Id, Nombre y Apellidos; y le voy a introducir tres filas de datos.

Hoja Excel

Ahora me voy al Visual Studio y creo un nuevo proyecto vacío en C#, al cual lo primero que hago es añadirle el fichero program.cs en donde describo el método estático main() como punto de inicio de la ejecución.

Creando un proyecto nuevo C# vacio

namespace GenbetaDevLinqToExcel
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Lo siguiente es abrir la localización del proyecto para mover o copiar el fichero excel que acabo crear, dentro de la carpeta física del código. Y añadirlo al proyecto como un item ya existente. Esto me va a facilitar la vida para después referenciar este fichero a la librería de lectura.

Añadir el fichero Excel al proyecto

Ahora entro en herramientas y abro el gestor de paquetes Nuget, y realizo una búsqueda online por el término "LinqToExcel". Obteniendo una librería que instalo en mí proyecto.

Linq to Excel en Nuget

Y ya estoy listo para empezar a tirar líneas de código, aunque me tocará hacer un par de configuraciones más en los proyectos y, tal vez, en el sistema operativo.

Leyendo Excel de forma sencilla

Podría hacer un tutorial muy básico mostrando solo una lectura, pero creo que el mínimo imprescindible es el obtener una colección de una entidad definida desde la Excel, pero sin entrar en las capacidades de automapeo de la propia librería LinqToExcel.

Así el siguiente paso es crear una clase que defina la entidad en donde voy a volcar los datos recuperados de la Excel y que voy a llamar EntidadHojaExcel.


    public class EntidadHojaExcel
    {
        public string Id { get; set; }
        public string Nombre { get; set; }
        public string Apellidos { get; set; }
    }

Después creo la clase que va leer la excel y que voy a llamar - después de mucho pensar - Excel. La cual va a tener un único método llamado ToEntidadHojaExcelList y que recibirá un único parámetro de tipo string con la dirección física del fichero excel que quiero leer.


using System.Collections.Generic;
using System.Linq;
using LinqToExcel;
public class Excel

namespace GenbetaDevLinqToExcel
{
    {
        public List ToEntidadHojaExcelList(string pathDelFicheroExcel)
        {
            var book = new ExcelQueryFactory(pathDelFicheroExcel);
            var resultado = (from row in book.Worksheet("Hoja1")
                             let item = new EntidadHojaExcel
                             {
                                 Id = row["Id"].Cast(),
                                 Nombre = row["Nombre"].Cast(),
                                 Apellidos = row["Apellidos"].Cast()
                             }
                             select item).ToList();

            book.Dispose();
            return resultado;
        }
    }
}

Te recuerdo que debes de asegurarte de estar utilizando los namespaces adecuados, los cuales en este caso es LinqToExcel, y también System.Linq.

A continuación voy a crear una nueva instancia del objeto que realiza las consultas a la Excel.


 var book = new ExcelQueryFactory(pathDelFicheroExcel);

Como siempre, aunque no sea TDD estricto, ha llegado el momento de crear el proyecto de Test que todo código debe tener, y que en Visual Studio es tan fácil como seleccionar su creación pulsando con el botón derecho encima del método.

No olvides nunca "Las pruebas no son opcionales". Sin pruebas no es válido ningún proyecto moderno.

En este momento me ha saltado un aviso en donde me dice que la referencia al proyecto a probar está mal, y eso es porque son diferentes las versiones de Framework destino a compilar . Pulsando con el botón derecho sobre el icono de propiedades y unificando el Target Framework a 4.5, se elimina la alerta y el malfuncionamiento.

Cambiando de framework a 4.5

En esta primerísima versión del test, voy a lanzar el método a probar, pero el Assert siempre devolverá True. Suena muy raro, pero tiene sentido cuando estás utilizando conexiones y quieres asegurarte que no hay ninguna excepción.

Error ACE.OLEDB.12

De hecho, en la mayoría de los casos, esté test saldrá verde. Pero en mi caso particular no ha sido así, devolviéndome un error que me indica que no tengo instalado el "Microsoft.ACE.OLEDB.12.0".

Para solucionar esto me descargo e instalo este fichero de Office 2007 y, al lanzar de nuevo el test, este pasa sin problemas.

El siguiente paso es hacer un nuevo test, o modificar el anterior (con algo tan pequeño no tiene mayor importancia), para pasarle el fichero que debe leer y cargar el resultado en una colección que me ha de devolver algún registro.

using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace GenbetaDevLinqToExcel.Tests
{
    [TestClass()]
    public class ExcelTests
    {
        [TestMethod()]
        public void ToEntidadHojaExcelListTest()
        {
            var fichero = @"c:\users\juan\documents\visual studio 2013\Projects\GenbetaDevLinqToExcel\GenbetaDevLinqToExcel\GenbetaDevEjemplo.xlsx";
            var excel = new Excel();

            var resultado = excel.ToEntidadHojaExcelList(fichero);

            Assert.IsTrue(resultado.Any());
        }
    }
}

Si lanzo el test, obviamente me devolverá rojo, porque por defecto (practico la programación que evita devolver null) la colección me vendrá vacía.

Y aquí se muestra toda la potencia de utilizar Linq para consumir información de una Excel. No solamente me traigo todos los registros de una Hoja específica, sino que lo mapeo directamente desde las columnas de la hoja de cálculo a las propiedades de la entidad de destino.

var resultado = (from row in book.Worksheet("Hoja1")
                             let item = new EntidadHojaExcel
                             {
                                 Id = row["Id"].Cast(),
                                 Nombre = row["Nombre"].Cast(),
                                 Apellidos = row["Apellidos"].Cast()
                             }
                             select item).ToList();

Si ahora vuelvo a lanzar el test... obtengo verde y he llegado al final de este breve tutorial.

Sin embargo, si tienes tiempo y/o ganas, puedes seguir investigando ya que la librería permite hacer Automapeado de las propiedades, lo cual puede hacer esta pieza de programación aún más útil.

Más información | Github de LinqToExcel
En Genbetadev | Linq, un lenguaje de consultas que marca diferencias, Diez librerías de PHP indispensables

Comentarios cerrados
Inicio