• 第十一节:Linq用法大全(二)


    一. 排序(orderby )

    1. 说明

       用于对查询出来的语句进行排序,orderby 默认是升序的;降序则用  orderby xxx descending。如果是多条件排序,则在orderby后面写多个排序条件,用 逗号 隔开,如果哪个字段是要降序排列,则在它后面加descending。

    2. 案例

    (1).单条件升序和降序

    例如:获取所有产品信息,并按照单价升序(降序)。

    升序
    var q = from p in db.Products
                orderby p.unitPirce
                select p;
    降序
    var q = from p in db.Products
                orderby p.unitPirce descending
                select p;

    (2).多条件复合排序

    例如:获取顾客信息,并依次按照城市名、顾客名进行升序排序。

    var q = from c in db.Customers
            orderby c.City,c.Name
            select c;

    例如:获取顾客信息,并依次按照城市名降序、顾客名升序排序。

    var q = from c in db.Customers
            orderby c.City descending, c.Name
            select c;

    例如:获取每一类产品中单价最高的产品信息,将产品按照类别ID进行升序排列。

    var q = from p in db.Procucts
                group p by p.KindId into g
                orderby g.Key
                select new {
                        g.Key,
                        HighestProducts=
                                from p2 in g
                                where p2.unitPrice == g.Max(m=>m.unitPrice)
                                select p2
                };

    二. 分组(group by)

     1. 说明-基本用法

       主要是用来对数据进行归类,可以按照类别进行输出,或者统计某个类别下的数量、最大值、最小值. 下面以一个简单的例子来说明。

    例如:将产品按照类别编号进行分类,并输出。

    var q = from p in db.Products
                group p by p.CategoryID into g
                select g;

    分析:from p in db.Products 表示从表中将产品对象取出来。group p by p.CategoryID into g 表示对p按CategoryID字段归类。 其中g.Key就是CategoryID,g代表以CategoryID为索引的多个集合,如下图:

    另外,其结果命名为g,一旦重新命名,p的作用域就结束了,所以,最后select时,只能select g。当然,也不必重新命名可以这样写:

    //不推荐
    var q =
        from p in db.Products
        group p by p.CategoryID;

    如何对上述结果进行遍历呢?

    var data = q.toList();  //这里不用延迟加载
    foreach (var gp in data)
    {
        //1.输出分类依据
       Console.WriteLine("类别编号为:{0}", gp.Key);   
        //2. 再次遍历输出类别下的内容
       foreach (var item in gp)
       {
          //do something
          Console.WriteLine($"产品名称:{item.pName},产品价格:{item.unitPrice}");
       }
    }

    同样是上面的例子,也可以这样输出匿名类。

    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new { CategoryID = g.Key, g }; 

    分析:在这句LINQ语句中,有2个property:CategoryID和g。这个匿名类,其实质是对返回结果集重新进行了包装。把g的property封装成一个完整的分组。如下图所示:

     

     如何遍历呢?

    var data = q.toList();  //这里不用延迟加载
    foreach (var gp in data)
    {
        //1.输出分类依据(这里 gp.CategoryID 等价于 gp.g.Key)
       Console.WriteLine("类别编号为:{0}", gp.CategoryID);   
        //2. 再次遍历输出类别下的内容
       foreach (var item in gp.g)
       {
          //do something
          Console.WriteLine($"产品名称:{item.pName},产品价格:{item.unitPrice}");
       }
    }

    2.  多列分组

    例如:按产品的分类,又按供应商分类进行分组,并输出产品信息。

    var categories =
        from p in db.Products
        group p by new
        {
            p.CategoryID,
            p.SupplierID
        }
         into g
         select new
         {
            g.Key,
            g
         };

    分析:既按产品的分类,又按供应商分类。在by后面,new出来一个匿名类。这里,Key其实质是一个类的对象,Key包含两个Property:CategoryID、SupplierID。用g.Key.CategoryID可以遍历CategoryID的值。

    补充一下多列分组的结果:

    CategorID   SupplierID

    c01    s01

    c01    s02

    c01    s02

    c02    s02

    c02    s01

    c02    s01

    将会分为四组

    (1). c01-s01: 1个产品

    (2). c01-s02: 2个产品

    (3). c02-s01: 2个产品

    (4). c01-s02: 1个产品

    3. 表达式分组

    例如:将产品分为两类,单价大于10的一类,单价小于10的一类。

    var categories =
        from p in db.Products
        group p by new { Criterion = p.UnitPrice > 10 } into g
        select g;

    4. 其它场景(分组求最大值,最小值、平均值、计数、求和等)

    //1.按照分类ID进行分组,并且求出每组中单价的最大值
    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new {
            g.Key,
            MaxPrice = g.Max(p => p.UnitPrice)
        };
    //2.按照分类ID进行分组,并且求出每组中单价的最小值
    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new {
            g.Key,
            MinPrice = g.Min(p => p.UnitPrice)
        };
    //3.按照分类ID进行分组,并且求出每组中单价的平均值
    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new {
            g.Key,
            AveragePrice = g.Average(p => p.UnitPrice)
        };
    //4. 求每组的单价总和
    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new {
            g.Key,
            TotalPrice = g.Sum(p => p.UnitPrice)
        };
    //5. 求每组的产品个数
    var q =
        from p in db.Products
        group p by p.CategoryID into g
        select new {
            g.Key,
            NumProducts = g.Count()
        };

    特别注意:

      以上关于group by的代码在传统的EF调用,和EFCore 2.2版本都也可以使用,但是在EFCore3.0 3.1中都不能使用了,报错。通过查源码GitHub,确实也存在这个问题,下面给出几种临时的解决方案:

    https://github.com/dotnet/efcore/issues/19894

    https://github.com/dotnet/efcore/issues/19663

    https://github.com/dotnet/efcore/issues?utf8=%E2%9C%93&q=groupby

    临时解决方案1:在groupby前面加 AsEnumerable

    var q2 = db.T_UserInfor.AsEnumerable().GroupBy(u => u.userSex).ToList();  //可以了

    3.x版本测试(重点)

     1                     var db = new ypfContext();
     2 
     3                     //报错 (Client side GroupBy is not supported.)
     4                     //var list1 = (from p in db.T_UserInfor
     5                     //             group p by p.userSex into g
     6                     //             select g).ToList();
     7 
     8                     //报错 ((GroupByShaperExpression错误)
     9                     //var list2 = (from p in db.T_UserInfor
    10                     //             group p by p.userSex into g
    11                     //             select new
    12                     //             {
    13                     //                 myKey = g.Key,
    14                     //                 g
    15                     //             }).ToList();
    16 
    17                     //报错
    18                     //var list3 = (from p in db.T_UserInfor
    19                     //             group p by new  { ISMore30 = p.userAge > 30 } into g
    20                     //             select new
    21                     //             {
    22                     //                 g.Key,
    23                     //                 g
    24                     //             }).ToList();
    25 
    26 
    27                     //可以
    28                     //var list3 = (from p in db.T_UserInfor
    29                     //             group p by p.userSex into g
    30                     //             select new
    31                     //             {
    32                     //                 g.Key,
    33                     //                 myCount=g.Count(),
    34                     //                 myAgeMax=g.Max(p=>p.userAge),
    35                     //                 myAgeMin=g.Min(p=>p.userAge),
    36                     //                 myAgeSum=g.Sum(p=>p.userAge),
    37                     //                 myAgeAvg=g.Average(p=>p.userAge)
    38                     //             }).ToList();
    39                     //foreach (var item in list3)
    40                     //{
    41                     //    Console.WriteLine($"Key:{item.Key},myCount:{item.myCount},myAgeMax:{item.myAgeMax},myAgeMin:{item.myAgeMin},myAgeSum:{item.myAgeSum},myAgeAvg:{item.myAgeAvg}");
    42                     //}
    43 
    44 
    45                     /******************************************下面是改造*****************************************************/
    46 
    47                     //1.可以
    48                     //var list1 = (from p in db.T_UserInfor.AsEnumerable()
    49                     //             group p by p.userSex into g
    50                     //             select g).ToList();
    51                     //foreach (var item in list1)
    52                     //{
    53                     //    Console.WriteLine($"分类为:{item.Key}");
    54                     //    Console.WriteLine($"详情为:");
    55                     //    foreach (var cItem in item)
    56                     //    {
    57                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    58                     //    }
    59                     //}
    60 
    61                     //2.可以
    62                     //var list2 = (from p in db.T_UserInfor.AsEnumerable()
    63                     //             group p by p.userSex into g
    64                     //             select new
    65                     //             {
    66                     //                 myKey = g.Key,
    67                     //                 g
    68                     //             }).ToList();
    69                     //foreach (var item in list2)
    70                     //{
    71                     //    Console.WriteLine($"分类为:{item.myKey}");
    72                     //    Console.WriteLine($"详情为:");
    73                     //    foreach (var cItem in item.g)
    74                     //    {
    75                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    76                     //    }
    77                     //}
    78 
    79                     //3.可以
    80                     //var list3 = (from p in db.T_UserInfor.AsEnumerable()
    81                     //             group p by new { ISMore30 = p.userAge > 30 } into g
    82                     //             select new
    83                     //             {
    84                     //                 g.Key,
    85                     //                 g
    86                     //             }).ToList();
    87                     //foreach (var item in list3)
    88                     //{
    89                     //    Console.WriteLine($"分类为:{item.Key}");
    90                     //    Console.WriteLine($"详情为:");
    91                     //    foreach (var cItem in item.g)
    92                     //    {
    93                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    94                     //    }
    95                     //}
    View Code

    2.x版本测试

     1                     var db = new ypfContext();
     2 
     3                     //可以
     4                     //var list1 = (from p in db.T_UserInfor
     5                     //             group p by p.userSex into g
     6                     //             select g).ToList();
     7                     //foreach (var item in list1)
     8                     //{
     9                     //    Console.WriteLine($"分类为:{item.Key}");
    10                     //    Console.WriteLine($"详情为:");
    11                     //    foreach (var cItem in item)
    12                     //    {
    13                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    14                     //    }
    15                     //}
    16 
    17                     //可以
    18                     //var list2 = (from p in db.T_UserInfor
    19                     //             group p by p.userSex into g
    20                     //             select new
    21                     //             {
    22                     //                 myKey = g.Key,
    23                     //                 g
    24                     //             }).ToList();
    25                     //foreach (var item in list2)
    26                     //{
    27                     //    Console.WriteLine($"分类为:{item.myKey}");
    28                     //    Console.WriteLine($"详情为:");
    29                     //    foreach (var cItem in item.g)
    30                     //    {
    31                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    32                     //    }
    33                     //}
    34 
    35                     //可以
    36                     //var list3 = (from p in db.T_UserInfor
    37                     //             group p by new { ISMore30 = p.userAge > 30 } into g
    38                     //             select new
    39                     //             {
    40                     //                 g.Key,
    41                     //                 g
    42                     //             }).ToList();
    43                     //foreach (var item in list3)
    44                     //{
    45                     //    Console.WriteLine($"分类为:{item.Key}");
    46                     //    Console.WriteLine($"详情为:");
    47                     //    foreach (var cItem in item.g)
    48                     //    {
    49                     //        Console.WriteLine($"{cItem.id},{cItem.userName},{cItem.userSex},{cItem.userAge}");
    50                     //    }
    51                     //}
    52 
    53 
    54                     //可以
    55                     //var list4 = (from p in db.T_UserInfor
    56                     //             group p by p.userSex into g
    57                     //             select new
    58                     //             {
    59                     //                 g.Key,
    60                     //                 myCount=g.Count(),
    61                     //                 myAgeMax=g.Max(p=>p.userAge),
    62                     //                 myAgeMin=g.Min(p=>p.userAge),
    63                     //                 myAgeSum=g.Sum(p=>p.userAge),
    64                     //                 myAgeAvg=g.Average(p=>p.userAge)
    65                     //             }).ToList();
    66                     //foreach (var item in list4)
    67                     //{
    68                     //    Console.WriteLine($"Key:{item.Key},myCount:{item.myCount},myAgeMax:{item.myAgeMax},myAgeMin:{item.myAgeMin},myAgeSum:{item.myAgeSum},myAgeAvg:{item.myAgeAvg}");
    69                     //}
    70 
    71 
    72 
    73                     /******************************************无须改造了*****************************************************/
    View Code

    临时解决方案2:更换groupby的位置

    三. Skip、Take、SkipWhile、TakeWhile

     1. Take/TakeWhile

    (1). Take: 获取集合的前n个元素。

    例如:将产品按照产品ID升序排列,并获取前10个元素。

    var q =(from p in db.Products
               orderby p.ProductId
               select p)
               .Take(10).toList();

    (2). TakeWhile:直到某一个条件成立就停止获取。

    例如:将产品按照产品ID升序排列,并获取元素到productId="008"为止。

    var q =(from p in db.Products
               orderby p.ProductId
               select p)
               .TakeWhile(p=>p.ProductId=="008").toList();

    2. Skip/SkipWhile

    (1). Skip: 跳过集合的前n个元素,求剩下的元素。

    例如:将产品按照产品ID升序排列,并获取除了前3个外的后续所有产品信息。

    var q =(from p in db.Products
               orderby p.ProductId
               select p)
               .Skip(3).toList();

    (2). SkipWhile: 跳过集合的前n个元素,直到符合某个条件为止,求剩下的元素。

    例如:将产品按照产品ID升序排列,并获取除了前n个外直到的productId=“007”后续所有产品信息。

    var q =(from p in db.Products
               orderby p.ProductId
               select p)
               .SkipWhile(p=>p.ProductId=="007").toList();

    PS:Skip和Take联合使用,组成分页案例。  公式: Skip((pageIndex-1)*pageSize).Take(pageSize)

    四. Any/All/Contains

    1. Any

    说明:用于判断集合中是否有元素满足某一条件。

    例如:返回没有订单的客户

    var q =
        from c in db.Customers
        where !c.Orders.Any()
        select c;

    对应的SQL语句

    SELECT *
    FROM [dbo].[Customers] AS [t0]
    WHERE NOT (EXISTS(
        SELECT NULL AS [EMPTY] FROM [dbo].[Orders] AS [t1]
        WHERE [t1].[CustomerID] = [t0].[CustomerID]
       ))

    2. All

    说明:用于判断集合中所有元素是否都满足某一条件。

    例如:返回所有订单都运往其所在城市的客户或未下订单的客户。

    var q =
        from c in db.Customers
        where c.Orders.All(o => o.ShipCity == c.City)
        select c;

    3. Contains 

    说明:用于查看包含关系、模糊查询等

    类比:SqlMethods.Like(c.CustomerID,"C%")  或 var data = dbContext.T_UserInfor.Where(u => EF.Functions.Like(u.userName, "%pf%")).ToList();

    (1). 集合中是否包含某一元素

     例如:查找"AROUT", "BOLID" 和 "FISSA" 这三个客户的订单。 这里相当于SQL语句中的in。

    string[] customerID_Set = new string[] { "AROUT", "BOLID", "FISSA" };
    var q = (
        from o in db.Orders
        where customerID_Set.Contains(o.CustomerID)
        select o).ToList();

    (2). 集合中包含多个元素

     例如:查找其所在城市为西雅图、伦敦、巴黎或温哥华的客户。

    string[] cities = 
        new string[] { "Seattle", "London", "Vancouver", "Paris" };
    var q = db.Customers.Where(p=>cities.Contains(p.City)).ToList();

    五. Concat/Union/Intersect/Except

    1. Concat 连接

      连接不同的集合,不会自动过滤相同项。多个集合中连接的字段的类型必须完全一致。   

    例如:求消费者和雇员的联系方式。

    var q = ( from c in db.Customers
                 select c.Phone    
                ).Concat(
                 from e in db.Employees
                 select e.HomePhone
               );

    PS:以上代码中的Phone和HomePhone的类型必须完全一样,这样才能进行连接,连接后仍旧是一个字段,最终使用的时候,要再括号一下,最后ToList();

    例如 : 求消费者和雇员的姓名和电话。

    var q = (
             from c in db.Customers
             select new
             {
                 Name = c.CompanyName,
                 c.Phone
             }
            ).Concat(
             from e in db.Employees
             select new
             {
                 Name = e.FirstName + " " + e.LastName,
                 Phone = e.HomePhone
             }
            );

    PS:Customers中的Name和Phone必须要和Employees中的Name和Phone类型完全相同。

    2. Union 合并

      连接多个不同的集合,自动过滤相同的选项,即求并集。  

    例如:求所有顾客和所有职员所在的国家。

    var q =(from c in db.Customers
            select c.Country)
            .Union
            (from e in db.Employees
             select e.Country);             

    3. Intersect 相交

      求多个几个集合之间的交集。

    例如:求所有顾客和所有职员公共所在的国家。

    var q =(from c in db.Customers
            select c.Country )
           .Intersect
           (from e in db.Employees
            select e.Country);  

    4. Except 排除

       排除相交项;延迟。即是从某集合中删除与另一个集合中相同的项。先遍历第一个集合,找出所有唯一的元素,然后再遍历第二个集合,返回第二个集合中所有未出现在前面所得元素集合中的元素

     例如:求职员单独所在的国家,即这些国家不在顾客所在的国家之内。

    var q =(from c in db.Customers
            select c.Country )
           .Except
           (from e in db.Employees
            select e.Country);  

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    input 框变成不可编辑的。
    git 首次往远程仓库提交项目过程。(使用idea操作)
    nacos 导入项目配置(yml文件)步骤
    instr MySQL数据库函数用法
    遍历 map 的方法
    基于分布式思想下的rpc解决方案(1)
    深入理解通信协议-(1)
    Tomcat(3)--性能优化
    并发编程(5)--并发容器
    并发编程(4)--显示锁和AQS
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/11693358.html
Copyright © 2020-2023  润新知