LINQ

什么是LINQ

LINQ(Language-Integrated Query,语言集成查询)是微软在 .NET 框架中引入的一种数据查询方法。它允许开发者使用类似于 SQL 的语法,在编程语言(如 C#、VB.NET)中直接对各种数据源(如集合、数据库、XML 等)进行查询操作。LINQ 的主要优势在于其统一的查询语法和与编程语言的紧密集成,使得数据操作更加简洁、类型安全且易于维护。

LINQ 的主要组成部分

LINQ 支持查询不同类型的数据源,主要包括以下几个部分:

  1. LINQ to Objects

    • 功能:用于对内存中的对象集合(如 List<T>ArrayDictionary<T> 等)进行查询和操作。它不需要任何外部资源,完全基于 .NET 集合框架。
    • 使用场景:当你有内存中的数据,如通过计算生成的数据或从文件中读取的数据时,使用 LINQ to Objects 进行过滤、排序、分组等操作非常方便。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
      // 查询所有偶数
      var evenNumbers = from num in numbers
      where num % 2 == 0
      select num;
      // 使用方法链语法
      var evenNumbersMethod = numbers.Where(num => num % 2 == 0).ToList();
  2. LINQ to SQL

    • 功能:用于查询 SQL Server 数据库,将数据库表映射为 .NET 类,允许使用 LINQ 语法执行查询操作。它的目标是让开发者用更直观的面向对象方式与数据库进行交互,而不是通过 SQL 字符串。
    • 使用场景:当你想要访问 SQL Server 数据库并进行 CRUD 操作时,可以使用 LINQ to SQL。你可以将数据库中的表与 .NET 对象一一映射,通过查询表达式来操作数据。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      using (var db = new DataContext())
      {
      // 查询来自 "Customers" 表的所有北京的客户
      var beijingCustomers = from customer in db.GetTable<Customer>()
      where customer.City == "Beijing"
      select customer;
      // 或者使用方法链语法
      var beijingCustomersMethod = db.GetTable<Customer>().Where(c => c.City == "Beijing").ToList();
      }
  3. LINQ to XML

    • 功能:用于处理 XML 数据,提供了一种方便的方式来查询、创建和修改 XML 文档。它与传统的 System.Xml 类库不同,更加简洁、直观。
    • 使用场景:当你需要读取、查询或生成 XML 数据时,LINQ to XML 是一种强大的工具。它可以在应用程序中动态解析和处理 XML 数据。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      8
      // 读取并查询 XML 文件
      XDocument doc = XDocument.Load("books.xml");
      var books = from book in doc.Descendants("book")
      where (string)book.Element("author") == "J.K. Rowling"
      select book;

      // 使用方法链语法
      var booksMethod = doc.Descendants("book").Where(b => (string)b.Element("author") == "J.K. Rowling");
  4. LINQ to Entities(Entity Framework)

    • 功能:基于 Entity Framework(EF)的 LINQ 查询方式,通过 ORM(对象关系映射)技术将数据库中的表映射为实体类,使得开发者可以使用 LINQ 对数据库进行查询和操作。LINQ to Entities 是 LINQ to SQL 的一个升级版,支持更多的数据库(不仅仅是 SQL Server)。
    • 使用场景:当你使用 Entity Framework 时,LINQ to Entities 可以让你通过实体类来查询数据库,而不需要直接编写 SQL 语句。
    • 示例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      using (var context = new MyDbContext())
      {
      // 查询价格大于 100 的所有产品
      var expensiveProducts = from product in context.Products
      where product.Price > 100
      select product;

      // 使用方法链语法
      var expensiveProductsMethod = context.Products.Where(p => p.Price > 100).ToList();
      }
  5. LINQ to DataSet

    • 功能:用于查询 DataSetDataTable 对象,它们通常从数据库或 XML 文件中填充数据。LINQ to DataSet 提供了一种方便的方法来查询 ADO.NET 数据结构。
    • 使用场景:当你使用传统的 ADO.NET 数据集和表结构时,LINQ to DataSet 可以让你用类似 SQL 的语法查询这些结构,而不必手动遍历行。
    • 示例
      1
      2
      3
      4
      DataSet ds = GetDataSet(); // 假设已经有数据集
      var products = from product in ds.Tables["Products"].AsEnumerable()
      where product.Field<decimal>("Price") > 100
      select product;

LINQ 的语法形式

LINQ 提供了两种主要的查询语法,每种都有其独特的用途:

  1. 查询表达式语法(Query Expression Syntax)

    • 描述:它是一种类 SQL 的语法,开发者使用 from, where, select, group by, orderby 等关键字来编写查询表达式。这种语法更加接近自然语言,特别适合熟悉 SQL 的开发者。
    • 优势:当你需要处理复杂的查询时,如分组、连接等,查询表达式语法会让代码更易读、更直观。
    • 例子
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

      // 查询所有偶数
      var evenNumbers = from num in numbers
      where num % 2 == 0
      select num;

      foreach (var number in evenNumbers)
      {
      Console.WriteLine(number); // 输出 2, 4, 6
      }
  2. 方法链语法(Method Syntax 或 Fluent Syntax)

    • 描述:这种语法基于扩展方法(即集合类上的 .Where().Select() 等方法),可以通过链式调用来构建查询。它通常更加灵活,适合函数式编程风格。
    • 优势:方法链语法在处理简单查询时十分高效,且与 .NET 的其他函数式编程方法(如 lambda 表达式)结合使用时非常强大。
    • 例子
      1
      2
      3
      4
      5
      6
      7
      8
      9
      var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };

      // 使用方法链语法查询所有偶数
      var evenNumbers = numbers.Where(num => num % 2 == 0);

      foreach (var number in evenNumbers)
      {
      Console.WriteLine(number); // 输出 2, 4, 6
      }

查询表达式语法和方法链语法的对比

特点 查询表达式语法 方法链语法
语法风格 类 SQL 函数式编程
适合场景 复杂查询(分组、连接、嵌套查询) 简单、灵活的查询(过滤、投影等)
代码可读性 类似自然语言,易于理解 更简洁,但对于复杂查询的可读性可能较差
表达的灵活性 稍微不如方法链灵活,某些高级操作需要转为方法链 灵活,支持所有扩展方法、lambda 表达式等
学习难度 熟悉 SQL 的人容易上手 需要掌握扩展方法和 lambda 表达式

常用的 LINQ 操作符

  • Where:筛选集合中的元素。
    1
    var result = numbers.Where(n => n % 2 == 0);
  • Select:投影(映射)操作,返回新的集合。
    1
    var squares = numbers.Select(n => n * n);
  • OrderBy/OrderByDescending:排序。
    1
    var ordered = numbers.OrderBy(n => n);
  • GroupBy:对集合分组。
    1
    var groups = numbers.GroupBy(n => n % 2);
  • Join:连接两个集合。
    1
    2
    3
    var result = from c in customers
    join o in orders on c.CustomerId equals o.CustomerId
    select new { c.Name, o.OrderDate };