Agrupar por varias columnas en consultas LINQ con C#

Muhammad Husnain 12 octubre 2023
  1. Introducción a LINQ
  2. Agrupar por columnas múltiples en consultas LINQ usando C#
Agrupar por varias columnas en consultas LINQ con C#

Este artículo proporciona una breve introducción a las consultas LINQ con C#. Además, analiza cómo agrupar los resultados por varias columnas mediante consultas LINQ.

Si ya está familiarizado con LINQ, puede omitir con seguridad la sección de introducción.

Introducción a LINQ

LINQ, que significa Language Integrated Query, es un método que nos brinda un método uniforme para acceder a datos de diferentes fuentes de datos, como bases de datos, matrices, XML y mucho más. Puede integrar todas las consultas en sí mismo.

Cuando los desarrolladores desarrollan una aplicación, necesitan algunos conocimientos adicionales además de un lenguaje de programación para adquirir datos de las fuentes de datos. Por ejemplo, si su fuente de datos es una base de datos, un programador necesita conocimientos de SQL.

De manera similar, el programador debe saber cómo analizar XML si la fuente de datos es un documento XML. Mientras que con LINQ, solo necesita el conocimiento sobre LINQ para adquirir datos de todas estas fuentes de datos.

Arquitectura LINQ

LINQ a objetos

LINQ to Objects significa que puede usar consultas LINQ para obtener los datos de una estructura de datos en memoria. Esta estructura de datos puede ser definida por el usuario, así como algunas API definidas por DotNet.

El único requisito para la estructura de datos es que debe devolver la colección en el tipo IEnumerable<T>.

Consideremos un ejemplo de LINQ to Objects:

using System;
using System.Linq;

class MyProgram {
  static void Main() {
    string[] list = { "apple", "ball", "aeroplane", "beautiful", "ancient" };

    var starts = from w in list
                 where w.StartsWith("a") select w;
    // Print words
    foreach (var word in starts) {
      Console.WriteLine(word);
    }
  }
}

Producción :

apple
aeroplane
ancient

En el fragmento de código anterior, hemos realizado una consulta LINQ para acceder a los datos de una matriz de cadenas. De esta forma, esta matriz se puede reemplazar con cualquier estructura de datos.

El beneficio de la consulta LINQ es que su sintaxis seguirá siendo la misma si cambia la estructura de datos en la parte posterior. La consulta seguirá siendo la misma; esta es la uniformidad proporcionada por LINQ.

LINQ a SQL

Para LINQ to ADO.Net, hay 3 subcomponentes. Pero nos centraremos principalmente en LINQ to SQL.

LINQ to SQL nos permite convertir la base de datos relacional en objetos. Hace que las operaciones de datos sean mucho más simples y rápidas.

El proceso que sigue es que primero se conecta a la base de datos, convierte las consultas LINQ en consultas SQL y luego ejecuta esas consultas SQL. El resultado devuelto por SQL se vuelve a convertir en objetos construidos por LINQ y luego se devuelve al usuario.

Proceso de LINQ a SQL

LINQ también rastrea los cambios en los datos de los objetos y sincroniza automáticamente esos cambios en la base de datos.

Cuando crea el componente LINQ to SQL en su proyecto, crea automáticamente las clases para todas las tablas de la base de datos. Después de eso, debe codificar las operaciones de conexión y base de datos.

Supongamos que tenemos una tabla para almacenar los datos de los empleados de una empresa. El nombre de la tabla es Emp y contiene los campos: Id, Name y Email.

Para usarlo como consultas LINQ, considere el siguiente fragmento de código:

using System;
using System.Linq;

namespace MyLINQExample {
   class LINQExample {
      static void Main(string[] args) {

         string connectString = System.Configuration.ConfigurationManager.            ConnectionStrings["LinqToSQLDBConnectionString"].ToString();
         LinqToSQLDataContext db = new LinqToSQLDataContext(connectString);
         Emp newEmp = new Emp();
         newEmp.name = "John";
         newEmp.email = "john@abccompany.com";
         newEmp.id = 3;
         //Add this new employee to the database
         db.Emps.InsertOnSubmit(newEmp);

         //To save changes in the database
         db.SubmitChanges();

         //Get the data of inserted employee
         Emp e = db.Emps.FirstOrDefault(e e.name.Equals("John"));

         Console.WriteLine("Emp Id = {0} , Name = {1}, Email = {2}",
                          e.id, e.name, e.email);

         Console.WriteLine("\nPress any key to continue.");
         Console.ReadKey();
      }
   }
}

En el código anterior, nos conectamos a la base de datos, creamos un objeto de contexto de datos y luego ejecutamos nuestra consulta en la base de datos.

Producción :

Emp Id = 3, Name = John, Email = john@abccompany.com

Uniones en LINQ

Al igual que las consultas SQL simples, también puede unir columnas mediante consultas LINQ. La operación de combinación se realiza cuando necesita los datos de diferentes tablas en función de alguna condición.

LINQ proporciona el operador join que puede unir fácilmente una o varias columnas. Consideremos que tenemos las siguientes dos clases:

public class Student {
  public int Stu_ID { get; set; }
  public string Stu_Name { get; set; }
  public int Class_ID { get; set; }
}

public class Grade {
  public int Grade_ID { get; set; }
  public string Grade_Name { get; set; }
}

En la función de controlador, creemos dos listas para cada clase de la siguiente manera:

IList<Student> students_list = new List<Student>() {
  new Student() { Stu_ID = 11, Stu_Name = "ABC", Class_ID = 1 },
  new Student() { Stu_ID = 12, Stu_Name = "DEF", Class_ID = 1 },
  new Student() { Stu_ID = 13, Stu_Name = "GHI", Class_ID = 2 },
  new Student() { Stu_ID = 14, Stu_Name = "JKL", Class_ID = 2 },
};

IList<Grade> gradeList = new List<Grade>() { new Grade() { Grade_ID = 1, Grade_Name = "Grade 1" },
                                             new Grade() { Grade_ID = 2, Grade_Name = "Grade 2" },
                                             new Grade() { Grade_ID = 3, Grade_Name = "Grade 3" } };

Ahora, si deseamos obtener los nombres de los estudiantes y sus grados, debemos unir estas dos tablas. Estas tablas se unirán en función de Class_ID y Grade_ID, respectivamente.

La consulta de unión será así:

var joinResult =
    from s in student_list join g in gradeList on s.Class_ID equals g.Grade_ID select new {
      StuName = s.Stu_Name, GradeName = g.Grade_Name
    };

Esto producirá el siguiente resultado:

ABC Grade 1
DEF Grade 1
GHI Grade 2
JKL Grade 2

Agrupar por columnas múltiples en consultas LINQ usando C#

De la misma forma, también podemos agrupar los datos en función de algún atributo. Esto se hace usando la cláusula GroupBy en la consulta LINQ.

El operador GroupBy devuelve un subconjunto de los elementos de una colección proporcionada en función de un valor clave. Los objetos IGrouping<TKey, TElement> representan cada grupo.

Además, el método GroupBy admite diferentes métodos de sobrecarga para que pueda utilizar el método de extensión apropiado en la sintaxis del método según sus requisitos.

Considere el siguiente código:

List<Student> student_List = new List<Student>() {
  new Student() { Stu_ID = 11, Stu_Name = "ABC", Age = 18, Subject = "Arts" },
  new Student() { Stu_ID = 12, Stu_Name = "DEF", Age = 19, Subject = "Science" },
  new Student() { Stu_ID = 13, Stu_Name = "GHI", Age = 18, Subject = "Arts" },
  new Student() { Stu_ID = 14, Stu_Name = "JKL", Age = 19, Subject = "Science" },
};

Supongamos que queremos obtener la lista de estudiantes agrupados por edad. La siguiente consulta lo hará por nosotros:

var result = from s in student_List group s by s.Age;

foreach (var ageGroups in result) {
  Console.WriteLine("Age Group: {0}", ageGroups.Key);
  foreach (Student s in ageGroups)  // Each group has inner collection
    Console.WriteLine("Student Name: {0}", s.Stu_Name);
}

Producción :

Age Group: 18
Student Name: ABC
Student Name: GHI
Age Group: 19
Student Name: DEF
Student Name: JKL

Del mismo modo, también podemos agrupar por varias columnas. Esto se hace de la siguiente manera:

var result = from s in student_List group s by new { s.Age, s.Subject };
foreach (var ageGroups in groupedResult) {
  Console.WriteLine("Group: {0}", ageGroups.Key);

  foreach (Student s in ageGroups)  // Each group has inner collection
    Console.WriteLine("Student Name: {0}", s.Stu_Name);
}

Esta consulta arrojará el siguiente resultado:

Group: {Age= 18, Subject="Arts"}
Student Name: ABC
Student Name: GHI
Group: {Age= 19, Subject="Science"}
Student Name: DEF
Student Name: JKL
Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn

Artículo relacionado - Csharp LINQ