美文网首页
2020-05-14 - Linq 查询

2020-05-14 - Linq 查询

作者: daiwei_9b9c | 来源:发表于2020-06-11 17:44 被阅读0次
    • Entity Framework Core 使用语言集成查询 (LINQ) 来查询数据库中的数据。

    https://docs.microsoft.com/zh-cn/ef/core/querying/

    • 客户端与服务器端评估

      • Entity Framework Core 会尝试尽可能在服务器上查询。
      • EF Core 支持在顶级投影中进行部分客户端评估(基本上为最后一次调用 Select())。 如果查询中的顶级投影无法转换为服务器,EF Core 将从服务器中提取任何所需的数据,并在客户端上评估查询的其余部分。

        指最后一次Select时, 如果遇到服务器不认识的转换,则将可以在客户端进行转换
        * EF Core 在顶级投影之外的任何位置检测到不能转换为服务器的表达式,则会引发运行时异常。
        > 即在最后一次 Select 之前,如果遇到不能转换的表达式,则抛出异常

      • 顶级投影中的客户端评估
        var blogs = context.Blogs .Select(blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog.Url) }) .ToList();
        上面代码中, 最后一个Select中的StandardizeUrl 函数不被服务器认识,所以将先在服务器查询所有数据,然后在客户端转换
      • 不支持的客户端评估
        var blogs = context.Blogs .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet")) .ToList();
        上面代码中, ToList为最后一次 Select, 而之前的 where 中包含不被服务器认识的函数 StandardizeUrl, 所以将抛出异常
      • 显式客户端评估
        a. 由于数据量小,因此在进行客户端评估时才不会大幅减弱性能。
        b. 所用的 LINQ 运算符不会进行任何服务器端转换
        c. 通过调用 AsEnumerable 或 ToList 等方法(若为异步,则调用 AsAsyncEnumerable 或 ToListAsync),以显式方式选择进行客户端评估
        d. AsEnumerable 将对结果进行流式传输, 而 ToList 会占用额外的内存
        var blogs = context.Blogs .AsEnumerable() .Where(blog => StandardizeUrl(blog.Url).Contains("dotnet")) .ToList();
        上面代码中, AsEnumerable 为最后一次 Select,
      • 内存泄漏
        在 Linq查询中,使用了实例中的常数, 而 Linq查询 会缓存表达式, 这使得实例无法释放, 因为其被缓存所使用;
    • 跟踪与非跟踪查询

      • 非跟踪查询
        var blogs = context.Blogs.AsNoTracking().ToList(); 或者变更整个 DbContext 为不跟踪
        context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
      • 标识解析

      EF Core 将在跟踪查询中执行标识解析。 当具体化实体时,如果 EF Core 已被跟踪,则会从更改跟踪器返回相同的实体实例。 如果结果中多次包含相同的实体,则每次会返回相同的实例。

      非跟踪查询不会使用更改跟踪器,也不会执行标识解析。 因此会返回实体的新实例

    • 复杂查询

      • join -- 连接2个表, 有关联比较条件

      将使用 inner join 关联2个表, 这个需要有关联条件

    var query = from photo in context.Set<PersonPhoto>()
                        join person in context.Set<Person>() on photo.PersonPhotoId equals person.PhotoId
                       select new { person, photo }
    
    • groupjoin -- 不支持,将抛出异常

    • SelectMany -- 连接2个表, 无关联条件

    a. 不引用外部条件 -- 两个数据源的笛卡尔乘积
    使用 cross join 关联2个表, 没有关联条件

    var query = from b in context.Set<Blog>()
                      from p in context.Set<Post>()
                      select new { b, p }
    

    b. 引用 where 子句中的外部
    下面将使用 inner join 关联2个表

    var query = from b in context.Set<Blog>()
                from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId)
                select new { b, p };
    

    下面使用了 DeaultIfEmpty(), 将使用 left join 关联2个表

    var query2 = from b in context.Set<Blog>()
                 from p in context.Set<Post>().Where(p => b.BlogId == p.BlogId).DefaultIfEmpty()
                 select new { b, p };
    

    c. 引用非 where 情况下的外部
    使用 Cross Join, 即 Post 无记录时, 无结果返回;

    var query = from b in context.Set<Blog>()
                from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title)
                select new { b, p };
    

    下面使用了 Outer Apply, 也没有关联条件,
    但是可以支持 left join 类似语法, 即 Post 无记录时, 也可能有记录返回

    var query2 = from b in context.Set<Blog>()
                 from p in context.Set<Post>().Select(p => b.Url + "=>" + p.Title).DefaultIfEmpty()
                 select new { b, p };
    
    • GroupBy

    GroupBy 运算符创建 IGrouping<TKey, TElement> 类型的结果, 由于任何数据库结构都无法表示 IGrouping,
    聚合运算符应用于返回标量的每个组时,该运算符可在关系数据库中转换为 SQL GROUP BY
    SQL GROUP BY 也会受到限制。 它要求只按标量值进行分组。
    因此, 投影只能包含分组键列或对列应用的任何聚合
    聚合运算符: Avg, Count, LongCount, Min, Max, Sum
    注意下面的 group by 和 最后一个的 select , 只按标量值分组, 投影只包含分组健 和 聚合运算函数

    var query = from p in context.Set<Post>() group p by p.AuthorId into g
                 select new { g.Key,  Count = g.Count() };
    

    分组后的聚合运算符 ( 即 into g 中的 g ) 出现在 Where 或 OrderBy(或其他排序方式)LINQ 运算符中。
    它在 SQL 中将 HAVING 子句用于 where 子句。

    var query = from p in context.Set<Post>() group p by p.AuthorId into g
                      where g.Count() > 0   orderby g.Key
                      select new { g.Key,  Count = g.Count() };;
    
    • LeftJoin

    注意, LeftJoin 的写法,
    join 后 Into 到一个别名1中, 然后 from 别名2 in 别名1.DefaultIfEmpty()

    var query = from b in context.Set<Blog>()
                      join p in context.Set<Post>() on b.BlogId equals p.BlogId into grouping
                     from p in grouping.DefaultIfEmpty()
                      select new { b, p };```

    相关文章

      网友评论

          本文标题:2020-05-14 - Linq 查询

          本文链接:https://www.haomeiwen.com/subject/bakxohtx.html