使用 C# 在 LINQ 查询中按多列分组

Muhammad Husnain 2023年1月30日 2022年7月18日
  1. LINQ 简介
  2. 使用 C# 在 LINQ 查询中按多列分组
使用 C# 在 LINQ 查询中按多列分组

本文简要介绍了使用 C# 进行的 LINQ 查询。此外,它还讨论了如何使用 LINQ 查询按多列对结果进行分组。

如果你已经熟悉 LINQ,则可以安全地跳过介绍部分。

LINQ 简介

LINQ 是 Language Integrated Query 的缩写,它为我们提供了一种统一的方法来访问来自不同数据源(如数据库、数组、XML 等)的数据。它本身可以集成所有查询。

当开发人员开发应用程序时,他们需要一些除编程语言之外的额外知识来从数据源获取数据。例如,如果你的数据源是数据库,则程序员需要了解 SQL。

同样,如果数据源是 XML 文档,程序员应该知道如何解析 XML。而使用 LINQ,你只需了解 LINQ 即可从所有这些数据源获取数据。

LINQ 架构

LINQ 到对象

LINQ to Objects 意味着你可以使用 LINQ 查询从内存数据结构中获取数据。此数据结构可以是用户定义的,也可以是一些 DotNet 定义的 API。

对数据结构的唯一要求是它应该返回 IEnummerable<T> 类型的集合。

让我们考虑一个 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);
      }
   }
}

输出:

apple
aeroplane
ancient

在上面的代码片段中,我们进行了一个 LINQ 查询来访问字符串数组中的数据。这样,这个数组就可以替换成任何数据结构。

LINQ 查询的好处是无论你更改后面的数据结构,它的语法都将保持不变。查询将保持不变;这是 LINQ 提供的统一性。

LINQ 到 SQL

对于 LINQ to ADO.Net,有 3 个子组件。但是,我们将主要关注 LINQ to SQL。

LINQ to SQL 允许我们将关系数据库转换为对象。它使数据操作更加简单和快捷。

它遵循的过程是它首先连接到数据库,将 LINQ 查询转换为 SQL 查询,然后运行这些 SQL 查询。从 SQL 返回的结果被转换回 LINQ 构造的对象,然后返回给用户。

LINQ to SQL 进程

LINQ 还跟踪对象数据的变化并自动同步数据库中的这些变化。

在项目中创建 LINQ to SQL 组件时,它会自动为所有数据库表创建类。之后,你需要为连接和数据库操作编写代码。

假设我们有一个用于存储公司员工数据的表。表名称为 Emp,包含以下字段:IdNameEmail

要将其用作 LINQ 查询,请考虑以下代码片段:

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();
      }
   }
}

在上面的代码中,我们连接到数据库,创建了一个数据上下文对象,然后让我们的查询在数据库上运行。

输出:

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

LINQ 中的连接

与简单的 SQL 查询一样,你也可以使用 LINQ 查询连接列。当你根据某些条件需要来自不同表的数据时,执行连接操作。

LINQ 提供了 join 运算符,可以轻松地连接单个或多个列。考虑我们有以下两个类:

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; }
}

在驱动函数中,让我们为每个类创建两个列表,如下所示:

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"}
};

现在,如果我们想得到学生的名字和他们的年级,我们需要连接这两个表。这些表将分别基于 Class_IDGrade_ID 连接。

连接查询将如下所示:

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
                                };

这将产生以下输出:

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

使用 C# 在 LINQ 查询中按多列分组

同样,我们也可以根据某些属性对数据进行分组。这是使用 LINQ 查询中的 GroupBy 子句完成的。

GroupBy 运算符根据键值返回所提供集合中元素的子集。IGrouping<TKey, TElement> 对象代表每个组。

此外,GroupBy 方法支持不同的重载方法,因此你可以根据你的要求在方法语法中使用适当的扩展方法。

考虑以下代码:

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" },
    };

假设我们要获取按年龄分组的学生列表。以下查询将为我们执行此操作:

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);
}

输出:

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

同样,我们也可以按多列分组。这是通过以下方式完成的:

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);
        }

此查询将产生以下输出:

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

相关文章 - Csharp LINQ