EntityFramework Core 3.0查询

前言

随着.NET Core 3.0的发布,EF Core 3.0也随之正式发布,关于这一块最近一段时间也没太多去关注,陆续会去对比以前版本有什么变化没有,本节咱们来看下两个查询。数据库

分组

咱们知道在EF Core 3.0版本以前,对于分组查询是在客户端评估,也就是说在内存中操做,在EF Core 3.0版本后对于分组查询能够翻译成SQL在数据库进行,可是事实状况真的是这样吗?接下来咱们来看下吧,以下给出代码例子。数组

    public class EFCoreDbContext : DbContext
    {
        public EFCoreDbContext()
        {

        }
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer(@"Server=.;Database=EFTest;Trusted_Connection=True;");
    }

    public class Blog
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<Post> Posts { get; set; }
    }

    public class Post
    {
        public int Id { get; set; }
        public int BlogId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        public Blog Blog { get; set; }
    }

接下来咱们在控制台进行以下查询:ide

            var context = new EFCoreDbContext();

            var posts = context.Posts.GroupBy(d => d.BlogId)
                .Select(g => new 
                {
                    id = g.Key,
                    count = g.Count()
                })
                .ToList();

上述咱们查询每一篇博客的文章数组,咱们经过SQL Profiler跟踪到上述示例代码最终翻译成的SQL如咱们所指望的那样,以下图:post

假设如今有这样一个场景:查询全部博客发表的第一篇博客文章。基于这种场景咱们须要对发表博客文章进行分组,而后取第一篇,因此接下来咱们进行以下查询:ui

            var context = new EFCoreDbContext();

            var posts = context.Posts.GroupBy(d => d.BlogId)
                .Select(g => g.FirstOrDefault())
                .ToList();

既然这样没法翻译,根据官方文档可使用Linq to Object进行查询《https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/》 ,那么咱们就修改为以下代码查询看看:spa

            var context = new EFCoreDbContext();

            var posts = context.Posts.GroupBy(d => d.BlogId).AsEnumerable()
                .Select(d => d.FirstOrDefault())
                .ToList();

咋客户端都没法支持了呢?咱们只是想查询全部博客列表中第一篇文章,按照咱们的理解,理论上是能够进行翻译的对不对,好比翻译成以下直接写的SQL语句:翻译

SELECT 
    Id,BlogId,Title,Content 
FROM (
  SELECT *
      ,ROW_NUMBER() OVER (
                     PARTITION BY BlogId 
                     ORDER BY Id
                ) AS [ROW NUMBER]
  FROM dbo.Posts
  ) groups
WHERE groups.[ROW NUMBER] = 1
ORDER BY groups.Id DESC

因此到这里咱们大概能够猜想出EF Core对分组查询支持的并非那么好,目前应该只支持简单的分组求和而已,稍微复杂一点则没法翻译,因此咱们仍是老老实实将分组仍是彻底放在客户端评估吧,以下:code

            var context = new EFCoreDbContext();

            var posts = context.Posts.ToList().GroupBy(d => d.BlogId)
                .Select(d => d.FirstOrDefault())
                .ToList();

 

查找

咱们能够经过 EF.Functions.Like 来进行模糊查询,咱们能够经过StartWith或EndWith来查询开头或结尾的数据,要是如今须要查询出博客文章标题中包含某一字符的文章列表,咱们又该如何查询呢?咱们想到经过IndexOf来查询,接下来咱们来看看:blog

            var context = new EFCoreDbContext();

            var posts = context.Posts.Where(d => d.Title.IndexOf('C') == 2).ToList();

难道咱们又只能将全部查询出来,而后在内存中操做吗?代码以下:索引

            var context = new EFCoreDbContext();

            var posts = context.Posts.ToList().Where(d => d.Title.IndexOf('C') == 2).ToList();

其实咱们只要将上述单引号修改双引号便可解决彻底在客户端评估的问题,以下:

            var context = new EFCoreDbContext();

            var posts = context.Posts.Where(d => d.Title.IndexOf("C") == 2).ToList();

根据咱们的查询描述,咱们明明是想查询在标题中查询指定字符,为什么对字符不能支持,只支持字符串呢,不知道官方是出于何种缘由。同时这里咱们也注意到,不管是MySQL仍是SQL Server等等,尽可能不要将表中列设置为可空,即便是可空也要设置为不可空,给定一个默认值便可,一旦数据量巨大时,会发现查询很慢,由于经过IS NULL或者IS NOT NULL不走索引致使。好比上述咱们查询的Title,咱们不管是经过Data Annotations仍是Fluent Api,都必须配置成不可空,好比这里咱们经过Data Annotations配置以下:

        [Required]
        public string Title { get; set; }

此时咱们继续进行上述查询时候,会发现对空值的判断已经没有了,同时也减小了查询语句,以下:

总结

请注意上述我所演示EF Core版本为3.0.1。本节我也只是经过简单的示例稍微给你们看了EF Core 3中一些小的问题,固然可能还存在其余的问题,更多细节等我后续研究会继续给出EF Core 3.x系列文章,感谢您的阅读,如有叙述不当或错误之处,还望指正,谢谢。

相关文章
相关标签/搜索