当前位置:   article > 正文

LINQ基础复习以及IQueryable的认识_isugarqueryable结合linq写法

isugarqueryable结合linq写法

一,LINQ的使用复习

  • 常用集合类的拓展方法

    LINQ关键的功能是提供了集合类的拓展方法,所有实现了IEnumberable 接口的类都可以使用这些方法,这些方法不是IEnumberable,而是以拓展方法的形式存在与System.Linq命名空间的静态类中。

这里定义一个用于测试的类

Employee{
    public int Id {get;set;}
    
    public string Name {get;set;}
    
    public int Age {get;set;}
    
    public bool Gender {get;set;}
    
    public double Salary {get;set;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1. 数据过滤筛选

    1. Where方法是用于根据条件对数据进行过滤的。

    2. IEnumberable<Employee> list1 = list.Where(e => e.Salary > 2500 && e.Age < 34);
      
      foreach(Employee e in list1)
      {
      	Console.WriteLine(e);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
  2. 获取数据条数

    1. Count()方法用于获取数据条数,它有两个重载方法,一个没有参数,另一个有Func<TSource,bool>predicate类型参数。没有参数的重载方法用于获取集合的数据条数,而有predicate参数的可以获取集合中符合predicate条件的数据条数。

    2. int count1 = list.Count(e => e.Salary > 5000 || e.Age < 30);
      int count1 = list.Where(e => e.Salary > 5000 || e.Age < 30).Count();
      
      • 1
      • 2
  3. 判断是否至少有一条满足条件的数据

    1. Any方法用于判断集合中是否至少有一条满足条件的数据,返回值为bool类型。Any方法同样有两个重载方法,一个没有参数的,一个是有Func<TSource,bool> predicate类型参数的。

    2. bool b1 = list.Any(e => e.Salary > 8000)
      bool b2 = list.Where(e => e.Salary > 8000).Any()
      
      • 1
      • 2
  4. 获取一条数据

    1. LINQ中有4组获取一条数据的方法,分别是Single、SingleOrDefault、First、FirstOrDefault,返回的都是符合条件的一条数据

    2. 同样,每组方法有两个重载方法,一个没有参数,一个有Func<TSource,bool> predicate类型参数的。

    3. 区别

      1. Single如果确定有且仅有一条满足要求的数据那么就用Single方法。如果没有满足条件的数据,或者满足条件的数据多于一条,Single方法就会抛出异常
      2. SingleOrDefault:如果确认最多只有一条满足要求的数据,那么就用SingleOrDefault方法。如果没有满足条件的数据,SingleOrDefault方法就会返回类型的默认值,如果满足条件的数据多于一条,SingleOrDefault就会抛出异常
      3. First: 如果满足条件的数据有一条或者多条,First方法就会返回第一条数据,如果没有满足条件的数据,First方法就会抛出异常
      4. FirstOrDefault:如果满足条件的数据有一条或者多条,FirstOrDefault方法就会返回第一条数据,如果没有满足条件的数据,FirstOrDefault方法就会满足返回类型的默认值
    4. 代码演示

      1. Employee e1 = list.Single(e => e.Id == 6)
        Console.WriteLine(e1);
        Employee? e2 = list.SinleOrDefault(e=>e.Id==9);
        if(e2 == null)
            Console.WriteLine("没有 Id == 9的数据");
        else
           Console.WriteLine(e2);
        Employee e3 = list.First(e=>e.Age > 30);
        Console.WriteLine(e3);
        Employee? e4 = list.FirstOrDefault(e=>e.Id>9999);
        if(e4 == null)
            Console.WriteLine("没有大于30岁的数据");
        else
           Console.WriteLine(e4);
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
  5. 排序

    1. OrderBy方法可以对数据进行正向排序,而OrderByDescending方法则可以对数据进行逆向排序

    2. Console.WriteLine("-------按照年龄正序排序----------")
      var orderedItem1 = list.OrderBy(e => e.Age);
      foreach(var item in orderedItem1)
      {
      	Console.WriteLine(item);
      }
      Console.WriteLine("-------按照年龄逆序排序----------")
      var orderedItem2 = list.OrderByDescending(e => e.Age);
      foreach(var item in orderedItem2)
      {
      	Console.WriteLine(item);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
  6. 限制结果集

    1. 限制结果集用来从集合中获取部分数据,其主要应用场景是分页查询,比如从第2条开始获取3条数。

    2. Skip(n)方法用于跳过n条数据,Take(n)方法用于获取n条数据。

    3. var orderedItem1 = list.Skip(2).Take(3);
      foreach(var item in orderedItem1)
      {
          Console.WriteLine(item);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
    4. Skip、Take方法也可以单独使用

  7. 聚合函数

    1. Max,Min,Average,Sum,Count,这些方法也可以和Where,Skip,Take等方法一起使用
  8. 分组

    1. GroupBy方法用来进行分组

      1. IEnumberable<IGrouping<TKey,TSource>> GroupBy<TSource.TKey>(this IEnumberable<TSource> source,Func<TSource,TKey> keySelector())
        
        • 1
    2. GroupBy方法的参数keySelector是一个分组表达式,GroupBy方法的返回值为IGrouping<TKey,TSource>类型IEnumberable。IGrouping是一个继承自IEnumberable的接口,IGrouping中唯一的成员就是Key属性,表示这一组数据的数据项。

    3. IEnumberable<IGrouping<int,Employee>> items = list.GroupBy(e=>e.Age);
      foreach(IGrouping<int,Employee> item in items)
      {
          int age = item.Key;
          int count = item.Count();
          int maxSalary = item.Max(e=>e.Salary);
          double avgSalary = item.Average(e=>e.Salary);
          Console.WriteLine($"年龄{item.Key},人数{count},最高工资{maxSalary},平均工资{avgSalary}");
      }   
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
  9. 投影

    1. 可以对集合使用Select方法进行投影操作,通俗来说就是把集合中的每一项转换为另外一种类型,Select方法的参数就是转换的表达式

    2. IEnumberable<int> ages = list.Select(e=> e.Age);
      
      Console.WriteLine(string.Join(",",ages))
      
      • 1
      • 2
      • 3
  10. 集合转换

    1. 集合操作的拓展方法返回值大多是IEnumberable类型,但是有一些地方需要数组类型或者List类型的变量,我们可以用ToArray和ToList方法分别把IEnumberable转换为数组和List类型

    2. Employee[] items = list.Where(e=>e.Salary > 3000 ).ToArray();
      List<Employee> items = list.Where(e=>e.Salary > 3000 ).ToList();
      
      • 1
      • 2

二,EF Core的原理探究

1.IQueryable的延迟执行

  • IQueryable只是代表一个“可以放到数据库服务器去执行的查询”,它没有立即执行,只是“可以被执行”而已。
  • 对于IQueryable接口调用非终结方法的时候不会执行查询,而调用终结方法的时候则会立即执行查询。
  • **终结方法:遍历、ToArray()、ToList()、Min()、Max()、Count()**等
  • 非终结方法:GroupBy()、OrderBy()、Include()、Skip()、Take()等。
  • 简单判断:一个方法的返回值类型如果是IQueryable类型,那么这个方法一般就是非终结方法,否则就是终结方法。

2.为什么要实现延迟执行

  • 可以在实际执行之前,分步构建IQueryable。
  • 比如:定义一个方法根据给定的天艇宁search Words>来查询匹配的书;如果searchAll参数是true,则书名或者作者名中含有给定的search Wordsi都匹配,否则只匹配书名;如果orderByPrice参数为true,则按照价格排序,否则就自然排序;upperPrice参数代表价格上限。
  • void QueryBooks(string searchWords,bool searchAll,boolorderByPrice,double upperPrice)
  • 试着传递不同参数,查看生成的$QL的不同。

3.IQueryable复用的应用之分页查询

  • 分页的实现
    • 1、Skip(3).Take(8)最好显式指定排序规则
    • 2、需要知道满足条件的数据的总条数:用IQueryable的复用LongCount和Count
    • 3、页数:long pageCount(long)Math.Ceiling(count * 1.0 / pageSize);
void OutputPage(int pageIndex,int pageSize)
{
    using TestDbContext ctx = new TestDbContext();
    //这里先把查询规则创建出来
    IQueryable<Book> books =ctx.Books.Where(b => !b.Title.Contains("张三"));
    //获取满足条件的数据总条数
    long count =books.LongCount();		
    //使用count * 1.0 / pageSize 可以计算出数据总页数,考虑到有可能最后一页不满,使用Ceiling()取整
    long pageCount = (long)Math.Ceiling(count * 1.0 / pageSize);
    Console.WriteLine("页数:"+pageCount);
    var pagedBooks = books.Skip((pageIndex - 1) * pageSize).Take(pageSize);
    foreach(var b in pageBooks)
    {
        Console.WriteLine(b.Id + ","+b.Title);
    }    
    
}    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这里的pageIndex代表页码,pageSize参数代表页大小。考虑到pageIndex序号是从1开始的,因此我们要使用Skip方法跳过(pageIndex-1)*pageSize条数据,再最多获取pageSize条数据,就可以获得正确的分页数据了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/134849
推荐阅读