语言集成查询

本页使用了标题或全文手工转换,现处于中国大陆简体模式
求闻百科,共笔求闻

语言集成查询(英语:Language Integrated Query缩写:LINQ),发音"link",是微软的一项技术,新增一种自然查询的SQL语法到.NET Framework的编程语言中,目前可支持C#以及Visual Basic .NET语言。2007年11月19日随.NET Framework 3.5发布了LINQ技术。

包括LINQ to Objects、LINQ to SQL、LINQ to Datasets、LINQ to Entities、LINQ to Data Source、LINQ to XML/XSD等。

语言风格

LINQ新增了多项语言的风格,来展示出查询语言的扩展性,例如:C#:

匿名类型

匿名类型(Anonymous type)是C# 3.0与Visual Basic 9.0新增的功能,它允许开发人员可以使用不具类型的方式创建新的数据结构,而真正的类型在编译时期,由C# (或VB) Compiler自动产生,并写入编译目标文件中,它可以让开发人员能够很简单利用匿名类型创建对象,LINQ中的select指令即是利用这种特性来创建回传对象。

匿名类型本质上是表达元组(tuple),采用值语义。

下列使用匿名类型的代码:

    [WebGet]
    public IQueryable<Categories> GetCategoryByName(string CategoryName)
    {
        try
        {
            var query = base.CurrentDataSource.Categories.Where
         ("it.CategoryName = @Name", new ObjectParameter[] { new ObjectParameter("Name", CategoryName) });
        }
        catch (Exception)
        {
            throw;
        }
        return query;
    }

会由编译器改写为:

    [WebGet]
    public IQueryable<Categories> GetCategoryByName(string CategoryName)
    {
        IQueryable<Categories> CS$1$0000; // 由編譯器改寫而成。
        try
        {
            CS$1$0000 = base.CurrentDataSource.Categories.Where
         ("it.CategoryName = @Name", new ObjectParameter[] { new ObjectParameter("Name", CategoryName) });
        }
        catch (Exception)
        {
            throw;
        }
        return CS$1$0000;
    }

标准查询运算符 (Standard query operators)

操作符 类别 语义 示例
Where 筛选操作符(Restriction) Where(Predicate) Dim lowNums = numbers.Where(Function(num) num < 5)
Select 投影操作符(Projection) Select(匿名函数) Dim lowNums = numbers.Select(Function(num) num*num)
SelectMany 投影操作符(Projection) 返回多行结果,用于多表的交叉连接(cross join) Dim res = Employees.SelectMany(Function(e) e.Family.Select(Function(c)c.name))
Skip 分块操作符(Partitioning) 跳过前n个元素 Dim res=data.Skip(4)
SkipWhile 分块操作符(Partitioning) 跳过起始处使条件为真的所有元素 Dim res=data.SkipWhile(Function(i) i%2 = 0)
Take 分块操作符(Partitioning) 返回开头之处的n个元素 Dim res=data.Take(3)
TakeWhile 分块操作符(Partitioning) 返回起始处使条件为真的所有元素 Dim res=data.TakeWhile(Function(i) i%3 = 0)
Join 连接操作符 内连接两个或多个表,仅限于Equals运算符 from sup in suppliers join cust in customers on sup.Country equals cust.Country
GroupJoin 连接操作符 类似于LEFT OUTER JOIN,右侧集合匹配于左侧集合键值的元素被分组 From cust In customers Group Join ord In orders On cust.CustomerID Equals ord.CustomerID Into CustomerOrders = Group, OrderTotal = Sum(ord.Total)
Concate 合并操作符 用于连接两个序列 returnValue = firstSeq.Concat(secondSeq)
OrderBy 排序操作符(Ordering) Dim query As IEnumerable(Of Person) = Persons.OrderBy(Function(p) p.Age)
OrderByDescending 排序操作符(Ordering)
ThenBy 排序操作符(Ordering)
ThenByDescending 排序操作符(Ordering)
Reverse 排序操作符(Ordering)
GroupBy 分组操作符 Dim numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}
Dim numberGroups = From num In numbers Group num By remainder5 = (num Mod 5) Into numGroup = Group Select New With {.Remainder = remainder5, .numbers = numGroup}
Distinct 集合操作符 去重复
Union 集合操作符 集合并
Intersect 集合操作符 集合交
Except 集合操作符 集合差
AsEnumerable 转换操作符 用于把一个IEnumerable的派生类型转化为IEnumerable类型
AsQueryable 转换操作符 IEnumerable(Of T)转化为IQueryable(Of T).
ToArray 转换操作符 转换为数组
ToList 转换操作符 转换为List
ToDictionary 转换操作符 转换为一对一的字典(键-值对的集合)
ToLookup 转换操作符 转换为一对多的字典(键-值集的集合)
OfType 转换操作符 获取指定类型的元素组成一个数组 object[] numbers = { null, 1.0, "two", 3, "four", 5, "six", 7.0 };
var doubles = numbers.OfType<double>();
Cast 转换操作符 把序列的所有元素转换为指定类型
SequenceEqual 相等操作符 两个序列的元素依次相同返回真。使用元素所属类的IEqualityComparer(Of T) 泛型界面做相等比较
First 元素操作符 返回序列第一个元素(或满足条件第一个元素),没有则异常
FirstOrDefault 元素操作符 返回序列第一个元素,没有则返回空或默认值
Last 元素操作符 返回序列最后一个元素,没有则异常
LastOrDefault 元素操作符 返回序列最后一个元素,没有则返回空或默认值
Single 元素操作符 返回序列唯一元素,如果没有元素或多个元素则异常
SingleOrDefault 元素操作符 返回序列唯一元素,如果没有元素或多个元素则空或默认值
ElementAt 元素操作符 返回序列指定元素,失败则异常
ElementAtOrDefault 元素操作符 返回序列指定元素,失败则空或默认值
DefaultIfEmpty 元素操作符 返回序列,如果序列为空则返回元素的默认值 For Each number As Integer In numbers.DefaultIfEmpty()〈br> output.AppendLine(number)
Next
All 序列元素数量操作符 序列所有元素满足条件则为真
Any 序列元素数量操作符 序列有一个元素满足条件则为真
Contains 序列元素数量操作符 是否包含一个元素
Count 统计操作符 计数,可选一个谓词 int oddNumbers = numbers.Count(n => n % 2 == 1);
LongCount 统计操作符 计数,返回Int64类型
Sum 统计操作符 求和,可选对一个lambda函数表达式 double totalChars = words.Sum(w => w.Length);
Min 统计操作符 最小值,可选对一个lambda函数表达式 int shortestWord = words.Min(w => w.Length);
Max 统计操作符
Average 统计操作符
Aggregate 统计操作符 参数为一个委托,在序列的每个元素上执行该委托。委托的第一个参数为当前累计值,第二个参数为当前元素,返回值为新的累计值 Dim reversed As String = words.Aggregate(Function(ByVal current, ByVal word) word & " " & current)
equals/Equals 关键字 用于Join子句
from/From 关键字
in/In 关键字 指出数据源
into/Into 关键字 用于Group By子句
key 关键字 用于Group By子句的无名类型
let 关键字 给表达式定义别名 From prod In products Let Discount = prod.UnitPrice * 0.1 Where Discount >= 50 Select prod.ProductName, prod.UnitPrice, Discount
Group 关键字 在GroupBy子句的Into中用于辨识分组结果 From num In numbers Group num By remainder5 = (num Mod 5) Into Group
Range 方法 产生一个整数序列 From n In Enumerable.Range(100, 50)
Repeat 方法 产生一个整数序列 From n In Enumerable.Repeat(7, 10)

LINQ的各式言语支持度

下列的言语支持LINQ。

注:C++/CLI尚未支持LINQ。但是有第三方的C++包[1],以及第三方的PHP[2]

LINQ的示例

一个简单例子:

using System;
using System.Linq;

namespace DuckTyping
{
    internal class Program
    {
        private static void Main()
        {
            int[] array = { 1, 5, 2, 10, 7 };  
            // Select squares of all odd numbers in the array sorted in descending order
            var results = from x in array
                                     where x % 2 == 1
                                     orderby x descending
                                     select x * x;
            foreach (var result in results)
            {
                Console.WriteLine(result); 
            }
        }
    }
}

输出: 49 25 1

另一个例子:

// the Northwind type is a subclass of DataContext created by SQLMetal
// Northwind.Orders is of type Table<Order>
// Northwind.Customers is of type Table<Customer>

Northwind db = new Northwind(connectionString);
 
// use 'var' keyword because there is no name for the resultant type of the projection
 
var q =  from o in db.Orders
         from c in db.Customers
         where o.Quality == "200" && (o.CustomerID == c.CustomerID)
         select new { o.DueDate, c.CompanyName, c.ItemID, c.ItemName };
 
// q is now an IEnumerable<T>, where T is the anonymous type generated by the compiler

foreach (var t in q)
{
    // t is strongly typed, even if we can't name the type at design time
 
    Console.WriteLine("DueDate Type = {0}", t.DueDate.GetType());
    Console.WriteLine("CompanyName (lowercased) = {0}", t.CompanyName.ToLower());
    Console.WriteLine("ItemID * 2 = {0}", t.ItemID * 2);
}

Visual Studio支持

LINQ目前由Visual Studio 2008、2010、2012、2013、2015、2017、2019支持。

语言扩展

微软同样提供了LINQExtender,允许用户在不了解LINQ实现细节的情况下,编写自己的LINQ扩展。 如:LINQ to Twitter,LINQ to Oracle,LINQ to Active Directory等

参考文献

  1. LINQ for C++. [2014-02-18]. 
  2. PHPLinq. [2014-02-18]. 

外部链接

参见