Trabajar con DataTable a través de LINQ: de novato a maestro en 20 minutos
\n\nImagine la situación: está escribiendo una aplicación en C#, carga datos de la base de datos en un DataTable, y luego… necesita filtrar filas por una condición compleja, agrupar por fecha o combinar dos tablas. El viejo y conocido DataTable.Select("...") con sus filtros de cadena se rompe en la segunda condición, y los bucles foreach convierten el código en espagueti.
¿Le suena familiar? Entonces bienvenido al mundo de las consultas LINQ a DataTable. Esta es su súper herramienta, que convierte el trabajo con datos tabulares en un código elegante, legible y potente. En esta guía lo desglosaremos todo: desde Where básico hasta Join y GroupBy avanzados. ¡Allá vamos!
\n\n
¿Qué es LINQ to DataSet y para qué sirve?
\n\nLINQ (Language Integrated Query) es un lenguaje de consultas integrado en C#. Su principal característica: escribe consultas a cualquier tipo de datos (arrays, listas, XML, bases de datos) de la misma manera, utilizando los operadores conocidos from, where, select.
Pero con DataTable hay un detalle: LINQ no se puede aplicar directamente. DataTable no implementa la interfaz IEnumerable<T>. La solución es el método AsEnumerable(), que convierte la tabla en una colección de objetos DataRow. Es con esta con la que trabaja LINQ.
Ventajas del enfoque:
\n- \n
- ✅ Seguridad de tipos: el compilador detecta errores en los nombres de las columnas \n
- ✅ Legibilidad: el código se parece a SQL, pero sigue siendo C# \n
- ✅ Potencia: filtrado, proyección, agrupación, ordenación en una sola línea \n
- ✅ Rendimiento: ejecución diferida (no carga datos innecesarios) \n
Vayamos directo al grano. Agregue en su proyecto una referencia a System.Data.DataSetExtensions (normalmente ya está) y adelante.
\n\n
Preparación de datos: nuestra tabla de prueba
\n\nPara no ser teóricos, crearemos un DataTable con datos de productos. El siguiente código es nuestra base para todos los ejemplos:
// 1. Creamos la tabla con columnas\nDataTable products = new DataTable("Products");\nproducts.Columns.Add("Id", typeof(int));\nproducts.Columns.Add("Name", typeof(string));\nproducts.Columns.Add("Category", typeof(string));\nproducts.Columns.Add("Price", typeof(decimal));\nproducts.Columns.Add("DateAdded", typeof(DateTime));\n\n// 2. Agregamos filas\nproducts.Rows.Add(1, "Portátil ASUS", "Electrónica", 55000, DateTime.Now.AddDays(-10));\nproducts.Rows.Add(2, "Ratón Logitech", "Electrónica", 2500, DateTime.Now.AddDays(-5));\nproducts.Rows.Add(3, "Libro 'C# in Depth'", "Libros", 1800, DateTime.Now.AddDays(-2));\nproducts.Rows.Add(4, "Auriculares Sony", "Electrónica", 12000, DateTime.Now.AddDays(-1));\nproducts.Rows.Add(5, "Cuaderno Moleskine", "Papelería", 1200, DateTime.Now.AddDays(-20));\nproducts.Rows.Add(6, "Bolígrafo Parker", "Papelería", 3500, DateTime.Now.AddDays(-15));\nproducts.Rows.Add(7, "Monitor Dell", "Electrónica", 32000, DateTime.Now.AddDays(-30));\n\nAhora tenemos 7 productos. Es hora de aplicar la magia de LINQ.
\n\n\n\n
Consultas LINQ básicas a DataTable
\n\n1. Filtrado (Where) — como SQL WHERE
\n\nSupongamos que necesita seleccionar todos los productos que cuestan más de 10 000 rublos. Sin LINQ, escribiría un bucle con una comprobación de row["Price"]. Con LINQ se ve así:
var expensiveProducts = products.AsEnumerable()\n .Where(row => row.Field<decimal>("Price") > 10000);\n\nforeach (var row in expensiveProducts)\n{\n Console.WriteLine($"{row["Name"]} - {row["Price"]} руб.");\n}\n// Salida: Portátil ASUS - 55000, Auriculares Sony - 12000, Monitor Dell - 32000\n\nPunto importante: use el método Field<T>("ColumnName") en lugar de la conversión directa (decimal)row["Price"]. Es más seguro: si la columna es DBNull, Fie