zoukankan      html  css  js  c++  java
  • LINQ-基础

    导航

    什么是LINQ

      语言集成查询 (LINQ)用于 .NET Framework 集合、SQL Server 数据库、ADO.NET 数据集和 XML 文档的查询,提供简洁、方便的查询操作 在 LINQ 查询中,始终会用到对象。 可以使用相同的基本编码模式来查询和转换 XML 文档、SQL 数据库、ADO.NET 数据集、.NET 集合中的数据以及对其有 LINQ 提供程序可用的任何其他格式的数据。

      LINQ 需要IEnumerable  IEnumerable<T>。支持 IEnumerable<T> 或派生接口 (如泛型 IQueryable<T> 的类型称为"可查询 类型"。

      在LINQ查询表达式包含三个子句:fromwhere 和 select (如果您熟悉 SQL,您会注意到这些子句的顺序与 SQL 中的顺序相反。)from子句指定数据源,where 子句应用筛选器,select 子句指定返回的元素的类型。 

      延迟执行查询变量本身只是存储查询命令。 实际的查询执行会延迟到在 foreach 语句中循环访问查询变量时发生。

      强制立即执行对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。 CountMaxAverage 和 First 就属于此类查询。 由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。 另外还要注意,这些类型的查询L返回单个值,而不是 IEnumerable 集合。在延迟执行查询之中,若要强制立即执行任意查询并缓存其结果,可以调用 ToList<TSource> 或 ToArray<TSource> 方法

     

    基本 LINQ 查询操作

    from:

      在 LINQ 查询中,第一步是指定数据源。 像在大多数编程语言中一样,在 C# 中,必须先声明变量,才能使用它。 在 LINQ 查询中,最先使用 from 子句的目的是引入数据源        (customers) 和范围变量 (cust)。

     var queryAllCustomers = from cust in customers
                            select cust;

    where:

    也许最常用的查询操作是应用布尔表达式形式的筛选器(where)。 此筛选器使查询只返回那些表达式结果为 true 的元素。 使用 where 子句生成结果。 实际上,筛选器指定从源序列中排除哪些元素。 

    var queryLondonCustomers = from cust in customers
                               where cust.City == "London"
                               select cust;

    当然,也会有多条件查询,那么就需要用到“AND”或者“OR”

    where cust.City=="London" && cust.Name == "Devon"

    where cust.City == "London" || cust.City == "Paris"

    orderby:

    子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。 例如,下面的查询可以扩展为按 Name 属性对结果进行排序。 因为 Name 是一个字符串,所以默认比较器执行从 A 到 Z 的字母排序。若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。

    var queryLondonCustomers3 = 
        from cust in customers
        where cust.City == "London"
        orderby cust.Name ascending
        select cust;

    group:

     使用 group 子句,您可以按指定的键分组结果。 例如,您可以指定结果应按 City 分组,以便位于伦敦或巴黎的所有客户位于各自组中。 在本例中,cust.City 是键。

     var queryCustomersByCity =
          from cust in customers
          group cust by cust.City;

    group 子句返回一个 IGrouping<TKey, TElement> 对象序列,这些对象包含零个或更多个与该组的键值匹配的项。 例如,可以按照每个字符串中的第一个字母对字符串序列进行分组。 在这种情况下,第一个字母是键且具有 char 类型,并且存储在每个 IGrouping<TKey, TElement> 对象的 Key 属性中。 编译器可推断该键的类型。

    // Query variable is an IEnumerable<IGrouping<char, Student>>
    var studentQuery1 =
        from student in students
        group student by student.Last[0];

    into:

    如果您想要对每个组执行附加查询操作,则可以使用 into 上下文关键字指定一个临时标识符。 使用 into 时,必须继续编写该查询,并最终用一个 select 语句或另一个 group 子句结束该查询,如下面的代码摘录所示:

    var studentQuery =
         from student in students
         let avg = (int)student.Scores.Average()
         group student by (avg == 0 ? 0 : avg / 10) into g
         orderby g.Key
         select g;   

    当您想要按照多个键对元素进行分组时,可使用复合键。 通过使用匿名类型或命名类型来存储键元素,可以创建复合键。 在下面的示例中,假定已经使用名为 surname 和 city 的两个成员声明了类 Person group 子句使得为每组具有相同姓氏和相同城市的人员创建一个单独的组。

    group person by new {name = person.surname, city = person.city};

    let

    在查询表达式中,存储子表达式的结果有时很有用,这样可以在随后的子句中使用。 可以使用 let 关键字完成这一工作,该关键字可以创建一个新的范围变量,并且用您提供的表达式的结果初始化该变量。 一旦用值初始化了该范围变量,它就不能用于存储其他值。 但如果该范围变量存储的是可查询的类型,则可以对其进行查询。

    join

    联接运算创建数据源中没有显式建模的序列之间的关联。 例如,您可以执行联接来查找位于同一地点的所有客户和经销商。 在 LINQ 中,join 子句始终针对对象集合而非直接针对数据库表运行。

     

    var innerJoinQuery =
        from cust in customers
        join dist in distributors on cust.City equals dist.City
        select new { CustomerName = cust.Name, DistributorName= dist.Name };

     

    使用 join 子句可以将来自不同源序列并且在对象模型中没有直接关系的元素相关联。 唯一的要求是每个源中的元素需要共享某个可以进行比较以判断是否相等的值。 例如,食品经销商可能具有某种产品的供应商列表以及买主列表。 例如,可以使用 join 子句创建该产品同一指定地区供应商和买主的列表。

    内部连接:下面的示例演示一个简单的内部同等联接。 此查询产生一个“产品名称/类别”对平面序列。 同一类别字符串将出现在多个元素中。 如果 categories 中的某个元素不具有匹配的 products,则该类别不会出现在结果中。

    var query = from person in people
       join cat in cats on person equals cat.Owner
       join dog in dogs on 
       new { Owner = person, Letter = cat.Name.Substring(0, 1) }
       equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) }
       select new { CatName = cat.Name, DogName = dog.Name };

    分组联接:含有 into 表达式的 join 子句称为分组联接。分组联接会产生一个分层的结果序列,该序列将左侧源序列中的元素与右侧源序列中的一个或多个匹配元素相关联。 分组联接没有等效的关系术语;它本质上是一个对象数组序列。如果在右侧源序列中找不到与左侧源中的元素相匹配的元素,则 join 子句会为该项产生一个空数组。 因此,分组联接基本上仍然是一种内部同等联接,区别只在于分组联接将结果序列组织为多个组。如果您只选择分组联接的结果,则可以访问各个项,但无法识别结果所匹配的键。 因此,通常更为有用的做法是选择分组联接的结果并放入一个也具有该键名的新类型中,如上一个示例所示。

    var innerGroupJoinQuery2 =
        from category in categories
        join prod in products on category.ID equals prod.CategoryID into prodGroup
        from prod2 in prodGroup
        where prod2.UnitPrice > 2.50M
        select prod2;

    左外部联接:在左外部联接中,将返回左侧源序列中的所有元素,即使它们在右侧序列中没有匹配的元素也是如此。 若要在 LINQ 中执行左外部联接,请将 DefaultIfEmpty 方法与分组联接结合起来,以指定要在某个左侧元素不具有匹配元素时产生的默认右侧元素。 可以使用 null 作为任何引用类型的默认值,也可以指定用户定义的默认类型。 下面的示例演示了用户定义的默认类型:

    var leftOuterJoinQuery =
        from category in categories
        join prod in products on category.ID equals prod.CategoryID into prodGroup
        from item in prodGroup.DefaultIfEmpty(new Product { Name = String.Empty, CategoryID = 0 })
        select new { CatName = category.Name, ProdName = item.Name };

    select :

    在查询表达式中,select 子句可以指定将在执行查询时产生的值的类型。 该子句的结果将基于前面所有子句的计算结果以及 select 子句本身中的所有表达式。 查询表达式必须以 select 子句或 group 子句结束。select 子句产生的序列的类型决定了查询变量 queryHighScores 的类型。 在最简单的情况下,select 子句仅指定范围变量。 这会使返回的序列包含与数据源具有相同类型的元素。 select 子句还提供了一种功能强大的机制,可用于将源数据转换(或投影)为新类型。

     

     

     

    Lambda 表达式

    Lambda 表达式是一个可用于创建委托或表达式树类型的匿名函数。 通过使用 lambda 表达式,可以写入可作为参数或返回为函数调用值的本地函数。 Lambda 表达式对于编写 LINQ 查询表达式特别有用。若要创建 Lambda 表达式,必须在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。 例如,lambda 表达式 x => x * x 指定名为 x 的参数并返回 x 的平方。 您可以按照以下示例将此表达式分配给委托类型:

    delegate int del(int i);
    static void Main(string[] args)
    {
        del myDelegate = x => x * x;
        int j = myDelegate(5); //j = 25
    }

    => 运算符具有与赋值运算符 (=) 相同的优先级,并且是右结合运算符。

    表达式在右边的 Lambda 表达式称为“Lambda 表达式”。 Lambda 表达式返回表达式的结果,并采用以下基本形式:

    (input parameters) => expression

    只有在 Lambda 有一个输入参数时,括号才是可选的;否则括号是必需的。 两个或更多输入参数由括在括号中的逗号分隔:

    (x, y) => x == y

    有时,编译器难于或无法推断输入类型。 如果出现这种情况,您可以按以下示例中所示方式显式指定类型:

    (int x, string s) => s.Length > x
     

    LINQ 中的查询语法和方法语法

      在表示语言集成查询 (LINQ) 使用 LINQ 性查询语法,文档中的多数查询编写。 但是,在中,当编译代码时,必须将查询语法转换方法需要 .NET 公共语言运行时 (CLR)。 这些方法调用标准查询运算符,的名称类似 WhereSelectGroupByJoinMax和 Average 可以调用这些方法直接使用方法语法而不是查询语法。查询语法和方法语法语义相同的,但是,许多人员发现查询语法更简单、更易于阅读。 某些查询必须表示为方法调用。 例如,必须使用方法调用表示检索元素的数量与指定的条件的查询。 还必须使用方法需要检索元素的最大值在源序列的查询。 System.Linq 命名空间中的标准查询运算符的参考文档通常使用方法语法。 因此,即使在开始编写 LINQ 查询时,熟悉如何在查询和查询表达式本身中使用方法语法也非常有用。

      “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法。 大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了 IEnumerable<T> 接口或 IQueryable<T> 接口。 标准查询运算符提供了包括筛选、投影、聚合、排序等功能在内的查询功能。

      共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable<T> 的对象上运行。 构成每组运算符的方是 Enumerable 和 Queryable类的静态成员。 这些方法被定义为作为方法运行目标的类型的“扩展方法”。 这意味着可以使用静态方法语法或实例方法语法来调用它们

      此外,许多标准查询运算符方法运行所针对的类型不是基于 IEnumerable<T> 或 IQueryable<T> 的类型。 Enumerable 类型定义两个此类方法,这些方法都在类型为 IEnumerable 的对象上运行。 利用这些方法(Cast<TResult>(IEnumerable) 和 OfType<TResult>(IEnumerable)),您将能够在 LINQ 模式中查询非参数化或非泛型集合。 这些方法通过创建一个强类型的对象集合来实现这一点。 Queryable 类定义两个类似的方法(Cast<TResult>(IQueryable) 和 OfType<TResult>(IQueryable)),这些方法在类型为 Queryable 的对象上运行。

      各个标准查询运算符在执行时间上有所不同,具体情况取决于它们是返回单一值还是值序列。 返回单一值的方法(例如 Average 和 Sum)会立即执行。 返回序列的方法会延迟查询执行,并返回一个可枚举的对象。对于在内存中集合上运行的方法(即扩展 IEnumerable<T> 的那些方法),返回的可枚举对象将捕获传递到方法的参数。 在枚举该对象时,将使用查询运算符的逻辑,并返回查询结果。与之相反,扩展 IQueryable<T> 的方法不会实现任何查询行为,但会生成一个表示要执行的查询的表达式树。 查询处理由源 IQueryable<T> 对象处理。可以在一个查询中将对查询方法的调用链接在一起,这就使得查询的复杂性可能会变得不确定。

    对数据进行排序:

    OrderBy按升序对值进行排序。orderby

    OrderByDescending按降序对值进行排序。orderby … descending

    Set 运算:

      

    a,b,b,c,d,c  -->  a,b,c,d

    Except:返回差集,差集是指位于一个集合但不位于另一个集合的元素。

    a,b,c,e
                 -->b
    a,c,d,e    

    Intersect:返回交集,交集是指同时出现在两个集合中的元素。

    a,b,c,e
                 -->a,c,e
    a,c,d,e  

    Union:返回并集,并集是指位于两个集合中任一集合的唯一的元素。

     

    a,b,c,e
                 -->a,b,c,d,e
    a,c,d,e  

     


     

     

     

     

  • 相关阅读:
    OpenCV之设计模式
    ca
    BMP结构详解
    Lucas–Kanade光流算法学习
    卡尔曼
    hash+链表
    文件操作
    查找
    fseek效率
    大家都说3C直连网络,3C网络是指什么呢?
  • 原文地址:https://www.cnblogs.com/Smilodon/p/3513409.html
Copyright © 2011-2022 走看看