LINQ(二)基本 LINQ 查询操作

本文讲述了linq查询常用的from/where/orderby/groupby/join/where字句的用法。

获取数据源&from

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

C#

 
//queryAllCustomers is an IEnumerable<Customer>
var queryAllCustomers = from cust in customers
                        select cust;
 
 

范围变量类似于 foreach 循环中的迭代变量,但在查询表达式中,实际上不发生迭代。 执行查询时,范围变量将用作对 customers 中的每个后续元素的引用。 因为编译器可以推断 cust 的类型,所以您不必显式指定此类型。

 

筛选&where

也许最常用的查询操作是应用布尔表达式形式的筛选器。 此筛选器使查询只返回那些表达式结果为 true 的元素。 使用 where 子句生成结果。 实际上,筛选器指定从源序列中排除哪些元素。 在下面的示例中,只返回那些地址位于伦敦的 customers

C#

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

您可以使用熟悉的 C# 逻辑 AND  OR 运算符来根据需要在 where 子句中应用任意数量的筛选表达式。例如,若要只返回位于“伦敦”AND 姓名为“Devon”的客户,您应编写下面的代码:

C#

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

若要返回位于伦敦或巴黎的客户,您应编写下面的代码:

C#

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

Order by

通常可以很方便地将返回的数据进行排序。 orderby 子句将使返回的序列中的元素按照被排序的类型的默认比较器进行排序。 例如,下面的查询可以扩展为按 Name 属性对结果进行排序。 因为 Name 是一个字符串,所以默认比较器执行从 A 到 Z 的字母排序。

C#

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

若要按相反顺序(从 Z 到 A)对结果进行排序,请使用 orderby…descending 子句。

 

分组&group by

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

C#

 
// 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 关键字来创建可进一步查询的标识符。 下面的查询只返回那些包含两个以上的客户的组:

C#

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

 

联接 jion

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

有关更多信息,请参见join 子句(C# 参考)

 

选择(投影)&select 子句

在查询表达式中,select 子句可以指定将在执行查询时产生的值的类型。 该子句的结果将基于前面所有子句的计算结果以及 select 子句本身中的所有表达式。 查询表达式必须以 select 子句或 group 子句结束。

下面的示例演示了查询表达式中的简单 select 子句。

C#

 

class SelectSample1

{  

    static void Main()

   {          

       //Create the datasource

       List<int> Scores = newList<int>() { 97, 92, 81, 60 };

 

       // Create the query.

       IEnumerable<int> queryHighScores =

           from score inScores

           where score > 80

           select score;

 

       // Execute the query.

       foreach (int i in queryHighScores)

       {

           Console.Write(i + "");

       }           

    }

}

在最简单的情况下,select 子句仅指定范围变量,这会使返回的序列包含与数据源具有相同类型的元素。不过,select 子句还提供了一种功能强大的机制,可用于将源数据转换(或投影)为新类型。下面的示例演示了 select 子句可能采用的所有不同形式。 在每个查询中,请注意 select 子句和查询变量(studentQuery1studentQuery2 等)的类型之间的关系。

C#

 

    class SelectSample2

    {

       // Define someclasses

       public class Student

       {

           public string First { get; set; }

           public string Last { get; set; }

           public int ID { get; set; }

           public List<int>Scores;

           public ContactInfo GetContactInfo(SelectSample2app, int id)

           {

                ContactInfo cInfo =

                    (from ci in app.contactList

                    where ci.ID== id

                    select ci)

                    .FirstOrDefault();

 

                returncInfo;

           }

 

           public override string ToString()

           {

                return First+ " " + Last + ":" + ID;

           }

       }

 

       public class ContactInfo

       {

           public int ID { get; set; }

           public string Email { get; set; }

           public string Phone { get; set; }

           public override string ToString() { return Email+ "," + Phone; }

       }

 

       public class ScoreInfo

       {

           public double Average { get; set; }

           public int ID { get; set; }

       }

 

       // The primary datasource

       List<Student> students = new List<Student>()

        {

            new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= newList<int>() {97, 92, 81, 60}},

            new Student {First="Claire", Last="O'Donnell", ID=112, Scores= newList<int>() {75, 84, 91, 39}},

            new Student {First="Sven", Last="Mortensen", ID=113, Scores= newList<int>() {88, 94, 65, 91}},

            new Student {First="Cesar", Last="Garcia", ID=114, Scores= newList<int>() {97, 89, 85, 82}},

       };

 

       // Separate datasource for contact info.

        List<ContactInfo> contactList = new List<ContactInfo>()

       {

           new ContactInfo {ID=111, Email="SvetlanO@Contoso.com", Phone="206-555-0108"},

           new ContactInfo {ID=112, Email="ClaireO@Contoso.com", Phone="206-555-0298"},

            newContactInfo {ID=113, Email="SvenMort@Contoso.com", Phone="206-555-1130"},

           new ContactInfo {ID=114, Email="CesarGar@Contoso.com", Phone="206-555-0521"}

       };

 

 

       static void Main(string[]args)

       {

           SelectSample2 app = new SelectSample2();

 

           // Produce a filteredsequence of unmodified Students.

           IEnumerable<Student> studentQuery1 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent;

 

           Console.WriteLine("Query1:select range_variable");

           foreach (Student s instudentQuery1)

           {

               Console.WriteLine(s.ToString());

           }

 

           // Produce a filteredsequence of elements that contain

           // only one propertyof each Student.

           IEnumerable<String> studentQuery2 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent.Last;

 

           Console.WriteLine("\r\nstudentQuery2: select range_variable.Property");

           foreach (string s in studentQuery2)

           {

                Console.WriteLine(s);

           }

 

           // Produce a filteredsequence of objects created by

            // a method call on each Student.

           IEnumerable<ContactInfo> studentQuery3 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent.GetContactInfo(app, student.ID);

 

           Console.WriteLine("\r\nstudentQuery3: select range_variable.Method");

           foreach (ContactInfo ci instudentQuery3)

           {

               Console.WriteLine(ci.ToString());

           }

 

           // Produce a filteredsequence of ints from

           // the internal arrayinside each Student.

           IEnumerable<int> studentQuery4 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent.Scores[0];

 

           Console.WriteLine("\r\nstudentQuery4: select range_variable[index]");

           foreach (int i in studentQuery4)

           {

                Console.WriteLine("First score = {0}", i);

           }

 

           // Produce a filteredsequence of doubles

           // that are theresult of an expression.

           IEnumerable<double> studentQuery5 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent.Scores[0] * 1.1;

 

           Console.WriteLine("\r\nstudentQuery5: select expression");

           foreach (double d in studentQuery5)

           {

                Console.WriteLine("Adjusted first score = {0}", d);

           }

 

           // Produce a filteredsequence of doubles that are

           // the result of a method call.

           IEnumerable<double> studentQuery6 =

                fromstudent in app.students

                wherestudent.ID > 111

                selectstudent.Scores.Average();

 

           Console.WriteLine("\r\nstudentQuery6: select expression2");

           foreach (double d in studentQuery6)

           {

                Console.WriteLine("Average = {0}", d);

           }

 

           // Produce a filteredsequence of anonymous types

           // that contain onlytwo properties from each Student.

           var studentQuery7 =

                fromstudent in app.students

                wherestudent.ID > 111

                select new { student.First, student.Last };

 

           Console.WriteLine("\r\nstudentQuery7: select new anonymous type");

           foreach (var item instudentQuery7)

           {

                Console.WriteLine("{0}, {1}", item.Last, item.First);

           }

 

           // Produce a filteredsequence of named objects that contain

           // a method returnvalue and a property from each Student.

           // Use named types ifyou need to pass the query variable

           // across a methodboundary.

           IEnumerable<ScoreInfo> studentQuery8 =

                fromstudent in app.students

                wherestudent.ID > 111

                select new ScoreInfo

                {

                    Average =student.Scores.Average(),

                    ID = student.ID

                };

 

            Console.WriteLine("\r\n studentQuery8: select new named type");

           foreach (ScoreInfo si instudentQuery8)

           {

                Console.WriteLine("ID = {0}, Average = {1}", si.ID, si.Average);

           }

 

           // Produce a filteredsequence of students who appear on a contact list

           // and whose averageis greater than 85.

           IEnumerable<ContactInfo> studentQuery9 =

                fromstudent in app.students

                wherestudent.Scores.Average() > 85

                join ci in app.contactList on student.ID equals ci.ID

                select ci;

 

           Console.WriteLine("\r\nstudentQuery9: select result of join clause");

           foreach (ContactInfo ci instudentQuery9)

           {

                Console.WriteLine("ID = {0}, Email = {1}", ci.ID, ci.Email);

           }

 

           // Keep the consolewindow open in debug mode

           Console.WriteLine("Pressany key to exit.");

           Console.ReadKey();

           }

        }

    /* Output

       Query1: select range_variable

       Claire O'Donnell:112

       Sven Mortensen:113

       Cesar Garcia:114

 

       studentQuery2: select range_variable.Property

       O'Donnell

       Mortensen

       Garcia

 

       studentQuery3: select range_variable.Method

       ClaireO@Contoso.com,206-555-0298

       SvenMort@Contoso.com,206-555-1130

       CesarGar@Contoso.com,206-555-0521

 

       studentQuery4: select range_variable[index]

       First score = 75

       First score = 88

       First score = 97

 

       studentQuery5: select expression

       Adjusted first score = 82.5

       Adjusted first score = 96.8

       Adjusted first score = 106.7

 

       studentQuery6: select expression2

       Average = 72.25

       Average = 84.5

       Average = 88.25

 

       studentQuery7: select new anonymous type

       O'Donnell, Claire

       Mortensen, Sven

       Garcia, Cesar

 

       studentQuery8: select new named type

       ID = 112, Average = 72.25

        ID = 113, Average = 84.5

       ID = 114, Average = 88.25

 

       studentQuery9: select result of join clause

       ID = 114, Email = CesarGar@Contoso.com

*/

 

 

如上一个示例中的 studentQuery8 所示,您有时可能希望所返回序列中的元素仅包含源元素的属性子集。 通过使返回的序列尽可能地小一些,可以降低内存需求,并提高查询的执行速度。 通过在 select 子句中创建一个匿名类型,并且借助于对象初始值设定项用源元素中的适当属性对该匿名类型进行初始化,可以达到此目的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赫曦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值