• Linq小记


    官网地址:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/linq/standard-query-operators-overview
    查询操作的三个部分

    所有 LINQ 查询操作都由以下三个不同的操作组成:

    获取数据源。
    
    创建查询。
    
    执行查询。
    

    下面的示例演示如何用源代码表示查询操作的三个部分。 为方便起见,此示例将一个整数数组用作数据源;但其中涉及的概念同样适用于其他数据源。

        class IntroToLINQ
       {        
          static void Main()
          {
        // The Three Parts of a LINQ Query:
        // 1. Data source.
        int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
    
        // 2. Query creation.
        // numQuery is an IEnumerable<int>
        var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;
    
               // 3. Query execution.
                foreach (int num in numQuery)
              {
                 Console.Write("{0,1} ", num);
              }
           }
        }
    
     在 LINQ 中,查询的执行与查询本身截然不同;换句话说,如果只是创建查询变量,则不会检索任何数据。
    

    强制立即执行
    对一系列源元素执行聚合函数的查询必须首先循环访问这些元素。 Count、Max、Average 和 First 就属于此类查询。 由于查询本身必须使用 foreach 以便返回结果,因此这些查询在执行时不使用显式 foreach 语句。 另外还要注意,这些类型的查询返回单个值,而不是 IEnumerable 集合。 下面的查询返回源数组中偶数的计数:

    var evenNumQuery = 
    from num in numbers
    where (num % 2) == 0
    select num;
    int evenNumCount = evenNumQuery.Count();
    

    要强制立即执行任何查询并缓存其结果,可调用 ToList 或 ToArray 方法。

    List<int> numQuery2 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToList();
    

    // or like this:
    // numQuery3 is still an int[]

    var numQuery3 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToArray();
    

    此外,还可以通过在紧跟查询表达式之后的位置放置一个 foreach 循环来强制执行查询。 但是,通过调用 ToList 或 ToArray,也可以将所有数据缓存在单个集合对象中。

    筛选
    或许,最常见的查询操作是以布尔表达式的形式应用筛选器。 筛选器使查询仅返回表达式为 true 的元素。 将通过使用 where 子句生成结果。可使用熟悉的 C# 逻辑 AND 和 OR 运算符,在 where 子句中根据需要应用尽可能多的筛选器表达式。 例如,若要仅返回来自“London”的客户 AND 该客户名称为“Devon”,可编写以下代码:
    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 子句用于对根据您指定的键所获得的结果进行分组。 例如,可指定按 City 对结果进行分组,使来自 London 或 Paris 的所有客户位于单独的组内。 在这种情况下,cust.City 是键。

       // queryCustomersByCity is an IEnumerable<IGrouping<string, Customer>>
      var queryCustomersByCity =
      from cust in customers
      group cust by cust.City;
    
      // customerGroup is an IGrouping<string, Customer>
      foreach (var customerGroup in queryCustomersByCity)
     {
      Console.WriteLine(customerGroup.Key);
      foreach (Customer customer in customerGroup)
      {
          Console.WriteLine("    {0}", customer.Name);
      }
     }
    

    使用 group 子句结束查询时,结果将以列表的形式列出。 列表中的每个元素都是具有 Key 成员的对象,列表中的元素根据该键被分组。 在循环访问生成组序列的查询时,必须使用嵌套 foreach 循环。 外层循环循环访问每个组,内层循环循环访问每个组的成员。
    如果必须引用某个组操作的结果,可使用 into 关键字创建能被进一步查询的标识符。 下列查询仅返回包含两个以上客户的组:

    // custQuery is an IEnumerable<IGrouping<string, Customer>>
    var custQuery =
    from cust in customers
    group cust by cust.City into custGroup
    where custGroup.Count() > 2
    orderby custGroup.Key
    select custGroup;
    

    联接
    联接操作在不同序列间创建关联,这些序列在数据源中未被显式模块化。 例如,可通过执行联接来查找所有位置相同的客户和分销商。 在 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 };
    

    在 LINQ 中,不必像在 SQL 中那样频繁使用 join,因为 LINQ 中的外键在对象模型中表示为包含项集合的属性。 例如 Customer 对象包含 Order 对象的集合。 不必执行联接,只需使用点表示法访问订单:
    from order in Customer.Orders...

    选择(投影)
    select 子句生成查询结果并指定每个返回的元素的“形状”或类型。 例如,可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。 当 select 子句生成除源元素副本以外的内容时,该操作称为投影。 使用投影转换数据是 LINQ 查询表达式的一种强大功能。

    语言集成查询 (LINQ) 不只是检索数据。 它也是用于转换数据的强大工具。 通过使用 LINQ 查询,可以使用源序列作为输入,并通过多种方式对其进行修改,以创建新的输出序列。 通过排序和分组,你可以修改序列本身,而无需修改这些元素本身。 但也许 LINQ 查询最强大的功能是创建新类型。 这可以在 select 子句中完成。 例如,可以执行下列任务:

    将多个输入序列合并为具有新类型的单个输出序列。
    
    创建其元素由源序列中每个元素的一个或多个属性组成的输出序列。
    
    创建其元素由对源数据执行的操作结果组成的输出序列。
    
    创建其他格式的输出序列。 例如,可以将数据从 SQL 行或文本文件转换为 XML。
    

    这只是几个例子。 当然,可以以各种方式在同一查询中组合这些转换。 此外,一个查询的输出序列可以用作新查询的输入序列。

    将多个输入联接到一个输出序列中
    可以使用 LINQ 查询创建包含元素的输出序列,这些元素来自多个输入序列。 以下示例演示如何组合两个内存中数据结构,但相同的原则可应用于组合来自 XML 或 SQL 或数据集源的数据。 假设以下两种类类型:

     class Student
      {
    public string First { get; set; }
    public string Last {get; set;}
    public int ID { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public List<int> Scores;
    }
    class Teacher
    {
    public string First { get; set; }
    public string Last { get; set; }
    public int ID { get; set; } 
    public string City { get; set; }
    }
    class DataTransformations
    {
    static void Main()
    {
        // Create the first data source.
        List<Student> students = new List<Student>()
        {
            new Student { First="Svetlana",
                Last="Omelchenko",
                ID=111,
                Street="123 Main Street",
                City="Seattle",
                Scores= new List<int> { 97, 92, 81, 60 } },
            new Student { First="Claire",
                Last="O’Donnell",
                ID=112,
                Street="124 Main Street",
                City="Redmond",
                Scores= new List<int> { 75, 84, 91, 39 } },
            new Student { First="Sven",
                Last="Mortensen",
                ID=113,
                Street="125 Main Street",
                City="Lake City",
                Scores= new List<int> { 88, 94, 65, 91 } },
        };
        // Create the second data source.
        List<Teacher> teachers = new List<Teacher>()
        {                
            new Teacher { First="Ann", Last="Beebe", ID=945, City="Seattle" },
            new Teacher { First="Alex", Last="Robinson", ID=956, City="Redmond" },
            new Teacher { First="Michiyo", Last="Sato", ID=972, City="Tacoma" }
        };        
        // Create the query.
        var peopleInSeattle = (from student in students
                    where student.City == "Seattle"
                    select student.Last)
                    .Concat(from teacher in teachers
                            where teacher.City == "Seattle"
                            select teacher.Last);
        Console.WriteLine("The following students and teachers live in Seattle:");
        // Execute the query.
        foreach (var person in peopleInSeattle)
        {
            Console.WriteLine(person);
        }        
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
      }
    

    }

    选择每个源元素的子集
    有两种主要方法来选择源序列中每个元素的子集:

    1、若要仅选择源元素的一个成员,请使用点操作。 在以下示例中,假设 Customer 对象包含多个公共属性,包括名为 City 的字符串。 在执行时,此查询将生成字符串的输出序列。    
    
    var query = from cust in Customers  
            select cust.City;  
    

    2、若要创建包含多个源元素属性的元素,可以使用带有命名对象或匿名类型的对象初始值设定项。 以下示例演示如何使用匿名类型封装每个 Customer 元素的两个属性:

    var query = from cust in Customer  
            select new {Name = cust.Name, City = cust.City};
    

    将内存中对象转换为 XML
    LINQ 查询可以方便地在内存中数据结构、SQL 数据库、ADO.NET 数据集和 XML 流或文档之间转换数据。 以下示例将内存中数据结构中的对象转换为 XML 元素。

      class XMLTransform
     {
        static void Main()
       {            
        // Create the data source by using a collection initializer.
        // The Student class was defined previously in this topic.
        List<Student> students = new List<Student>()
        {
            new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
            new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
            new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
        };
        // Create the query.
        var studentsToXML = new XElement("Root",
            from student in students
            let scores = string.Join(",", student.Scores)
            select new XElement("student",
                       new XElement("First", student.First),
                       new XElement("Last", student.Last),
                       new XElement("Scores", scores)
                    ) // end "student"
                ); // end "Root"
        // Execute the query.
        Console.WriteLine(studentsToXML);
    
        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
       }
     }
    

    此代码生成以下 XML 输出:

        <Root>  
      <student>  
    <First>Svetlana</First>  
    <Last>Omelchenko</Last>  
    <Scores>97,92,81,60</Scores>  
      </student>  
      <student>  
    <First>Claire</First>  
    <Last>O'Donnell</Last>  
    <Scores>75,84,91,39</Scores>  
      </student>  
      <student>  
      <First>Sven</First>  
       <Last>Mortensen</Last>  
        <Scores>88,94,65,91</Scores>  
      </student>  
    </Root>  
    

    LINQ 查询操作中的类型关系
    若要有效编写查询,应了解完整的查询操作中的变量类型是如何全部彼此关联的。 如果了解这些关系,就能够更容易地理解文档中的 LINQ 示例和代码示例。 另外,还能了解在使用 var 隐式对变量进行类型化时的后台操作。
    LINQ 查询操作在数据源、查询本身及查询执行中是强类型化的。 查询中变量的类型必须与数据源中元素的类型和 foreach 语句中迭代变量的类型兼容。 此强类型保证在编译时捕获类型错误,以便可以在用户遇到这些错误之前更正它们。
    不转换源数据的查询

    下图演示不对数据执行转换的 LINQ to Objects 查询操作。 源包含一个字符串序列,查询输出也是一个字符串序列

    1、数据源的类型参数决定范围变量的类型。

    2、所选对象的类型决定查询变量的类型。 此处的 name 是一个字符串。 因此,查询变量是一个 IEnumerable

    3、在 foreach 语句中循环访问查询变量。 因为查询变量是一个字符串序列,所以迭代变量也是一个字符串

    转换源数据的查询

    下图演示对数据执行简单转换的 LINQ to SQL 查询操作。 查询将一个 Customer 对象序列用作输入,并只选择结果中的 Name 属性。 因为 Name 是一个字符串,所以查询生成一个字符串序列作为输出。

    1、数据源的类型参数决定范围变量的类型。

    2、select 语句返回 Name 属性,而非完整的 Customer 对象。 因为 Name 是一个字符串,所以 custNameQuery 的类型参数是 string,而非 Customer。

    3、因为 custNameQuery 是一个字符串序列,所以 foreach 循环的迭代变量也必须是 string。

    下图演示稍微复杂的转换。 select 语句返回只捕获原始 Customer 对象的两个成员的匿名类型。

    1、数据源的类型参数始终为查询中范围变量的类型。

    2、因为 select 语句生成匿名类型,所以必须使用 var 隐式类型化查询变量。

    3、因为查询变量的类型是隐式的,所以 foreach 循环中的迭代变量也必须是隐式的。

    让编译器推断类型信息
    虽然需要了解查询操作中的类型关系,但是也可以选择让编译器执行全部工作。 关键字 var 可用于查询操作中的任何本地变量。 下图与前面讨论的第二个示例相似。 但是,编译器为查询操作中的各个变量提供强类型。

  • 相关阅读:
    Android学习笔记04-Activity及Activity生命周期
    Android学习笔记03-学习过程中碰到的一些问题及解决方法
    Android学习笔记--生命周期
    Android学习笔记01
    Android学习笔记--项目框架介绍
    Android学习笔记- Animation动画
    Android学习笔记02-AndroidManifest.xml文件解析
    cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded 解决方法
    jvm 03-java堆内存模型
    jvm 02-java对象访问模式
  • 原文地址:https://www.cnblogs.com/caozhengze/p/10243401.html
Copyright © 2020-2023  润新知