一个Entity Framework Core的性能优化案例

概要

本文提供一个EF Core的优化案例,主要介绍一些EF Core常用的优化方法,以及在优化过程中,出现性能反复的时候的解决方法,并澄清一些对优化概念的误解,例如AsNoTracking并不包治百病。

本文使用的是Dotnet 6.0和EF Core 7.0。

代码及实现

背景介绍

本文主要使用一个图书和作者的案例,用于介绍优化过程。

  • 一个作者Author有多本自己写的的图书Book
  • 一本图书Book有一个发行商Publisher
  • 一个作者Author是一个系统用户User
  • 一个系统用户User有多个角色Role

本实例中Author表和Book数据量较大,记录数量全部过万条,其它数据表记录大概都是几十或几百条。具体实体类定义请见附录。

查询需求

我们需要查找写书最多的前两名作家,该作家需要年龄在20岁以上,国籍是法国。需要他们的FirstName, LastName, Email,UserName以及在1900年以前他们发行的图书信息,包括书名Name和发行日期Published。

基本优化思路

本人做EF Core的复杂查询优化,并不推荐直接查看生成的SQL代码,我习惯按照如下方式进行:

首先,进行EF的LINQ代码检查(初筛),找到明显的错误。

  1. 查看代码中是否有基本错误,主要针对全表载入的问题。例如EF需要每一步的LINQ扩展方法的返回值都是IQueryable类型,不能有IEnumerable类型;
  2. 查看是否有不需要的栏位;
  3. 根据情况决定是否加AsNoTracking,注意这个东西有时候加了也没用;

其次,找到数据量较大的表,进行代码整理和针对大数据表的优化(精细化调整)

  1. 在操作大数据表时候,先要进行基本的过滤;
  2. 投影操作Select应该放到排序操作后面;
  3. 减少返回值数量,推荐进行分页操作;

本人推荐一旦出现性能反复的时候或者代码整体基本完成的时候,再去查看生成的SQL代码。

初始查询代码

public  List<AuthorWeb> GetAuthors() {
     using var dbContext = new AppDbContext();
     var authors = dbContext.Authors
                 .Include(x => x.User)
                  .ThenInclude(x => x.UserRoles)
                  .ThenInclude(x => x.Role)
                  .Include(x => x.Books)
                  .ThenInclude(x => x.Publisher)
                  .ToList()
                  .Select(x => new AuthorWeb
                  {
                      UserCreated = x.User.Created,
                      UserEmailConfirmed = x.User.EmailConfirmed,
                      UserFirstName = x.User.FirstName,
                      UserLastActivity = x.User.LastActivity,
                      UserLastName = x.User.LastName,
                      UserEmail = x.User.Email,
                      UserName = x.User.UserName,
                      UserId = x.User.Id,
                      RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                      BooksCount = x.BooksCount,
                      AllBooks = x.Books.Select(y => new BookWeb
                      {
                          Id = y.Id,
                          Name = y.Name,
                          Published = y.Published,
                          ISBN = y.ISBN,
                          PublisherName = y.Publisher.Name
                      }).ToList(),
                      AuthorAge = x.Age,
                      AuthorCountry = x.Country,
                      AuthorNickName = x.NickName,
                      Id = x.Id
                  })
                  .ToList()
                  .Where(x => x.AuthorCountry == "France" && x.AuthorAge == 20)
                  .ToList();

     var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in orderedAuthors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }

Benchmark测试后,系统资源使用情况如下:

在这里插入图片描述

代码性能非常差,内存消耗很大,一次执行就要消耗190MB,执行时间超过2s。如果是放到WebAPI里面调用,用户会有明显的卡顿感觉;如果面临高并发的情况,很可得会造成服务器资源紧张,返回各种500错误。

优化代码

初筛

按照我们的优化思路,在查看上面的代码后,发现一个严重的问题。

虽然每次LINQ查询返回都是IQueryable类型,但是源码中有多个ToList(),尤其是第一个,它的意思是将Author, Book,User,Role,Publisher等多个数据表的数据全部载入,前面已经说了,Author, Book两张表的数据量很大,必然影响性能。

我们需要删除前面多余的ToList(),只保留最后的即可。请参考附录中的方法GetAuthors_RemoveToList()。

在GetAuthors_RemoveToList()基础上,对照用户的需求,发现查询结果中包含了Role相关的信息和很多Id信息,但是查询结果并不需要这些,因此必须删掉。请参考附录中的方法GetAuthorsOptimized_RemoveColumn()

在GetAuthorsOptimized_RemoveColumn的基础上,我们再加入AsNoTracking方法。请参考附录中的方法GetAuthorsOptimized_AsNoTracking()

我们在Benchmark中,测试上面提到的三个方法,直接结果如下:

在这里插入图片描述

从Benchmark的测试结果上看,删除多余ToList方法和删除多余的栏位,确实带来了性能的大幅提升。

但是增加AsNoTracking,性能提反而下降了一点。这也说明了AsNoTracking并不是适用所有场景。Select投影操作生成的AuthorWeb对像,并不是EF管理的,与DbContext无关,它只是作为前端API的返回值。相当于EF做了没有用的事,所以性能略有下降。

代码进一步调整

初筛阶段完成后,下面对代码进一步整理

下面Take和Order操作可以并入基本的查询中,Take可以帮助我们减少返回值的数量。请见 GetAuthorsOptimized_ChangeOrder()方法。

var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();

在GetAuthorsOptimized_ChangeOrder基础上,对于dbContext.Authors,Author是一张数据量很大的表,我们需要在其进行联表操作前,先过滤掉不需要的内容,所以我们可以把Where前提,还有就是将排序操作放到投影的Select前面完成。请见 GetAuthorsOptimized_ChangeOrder方法。

上面的两个优化方法的执行结果如下:

在这里插入图片描述
可以看到性略能有提升。

下面我们为了进一步提升性能,可以查看一下生成的SQL代码,看看是否还有优化的空间。

GetAuthorsOptimized_ChangeOrder方法生成的SQL如下:

      SELECT [u].[FirstName], [u].[LastName], [u].[Email], [u].[UserName], [t].[
BooksCount], [t].[Id], [u].[Id], [b].[Name], [b].[Published], [b].[Id], [t].[Age
], [t].[Country]
      FROM (
          SELECT TOP(@__p_0) [a].[Id], [a].[Age], [a].[BooksCount], [a].[Country
], [a].[UserId]
          FROM [Authors] AS [a]
          WHERE [a].[Country] = N'France' AND [a].[Age] >= 20
          ORDER BY [a].[BooksCount] DESC
      ) AS [t]
      INNER JOIN [Users] AS [u] ON [t].[UserId] = [u].[Id]
      LEFT JOIN [Books] AS [b] ON [t].[Id] = [b].[AuthorId]
      ORDER BY [t].[BooksCount] DESC, [t].[Id], [u].[Id]

从生成SQL来看,Author表在使用之前过滤掉了相关的内容,但是直接Left Join了[Books]这个大表。我们可以按照前面提到的1900年以前的查询要求,在左联之前先过滤一下,请参考 GetAuthorsOptimized_SelectFilter方法。

该方法执行后,生成的SQL如下:

      SELECT [u].[FirstName], [u].[LastName], [u].[Email], [u].[UserName], [t].[
BooksCount], [t].[Id], [u].[Id], [t0].[Name], [t0].[Published], [t0].[Id], [t].[
Age], [t].[Country]
      FROM (
          SELECT TOP(@__p_1) [a].[Id], [a].[Age], [a].[BooksCount], [a].[Country
], [a].[UserId]
          FROM [Authors] AS [a]
          WHERE [a].[Country] = N'France' AND [a].[Age] >= 20
          ORDER BY [a].[BooksCount] DESC
      ) AS [t]
      INNER JOIN [Users] AS [u] ON [t].[UserId] = [u].[Id]
      LEFT JOIN (
          SELECT [b].[Name], [b].[Published], [b].[Id], [b].[AuthorId]
          FROM [Books] AS [b]
          WHERE [b].[Published] < @__date_0
      ) AS [t0] ON [t].[Id] = [t0].[AuthorId]
      ORDER BY [t].[BooksCount] DESC, [t].[Id], [u].[Id]

在左联之前,确实进行了过滤,该方法的性能测试如下:

在这里插入图片描述
在避免Book表直接进行左联后,性能有所提升。

最后一个优化点,是在EF Core 5.0里面提供了带Filter功能的Include方法,也可以用于本案例的优化,但是该特性但是存在一些局限性,具体请参考EF Core中带过滤器参数的Include方法

但是此方法又涉及了将IQueryable转换成IEnumerable的操作,最后要将生成的Author对象全部转换成AuthorWeb对象。代码过于繁琐,而且带来的性能提升也不明显。因此放弃这个点。

dbContext.Authors
   .AsNoTracking()
   .Include(x => x.Books.Where(b => b.Published < date))
   ......

结论

从这个优化过程来看,其实对性能提升最大的贡献就是删除多余的ToList(),避免全表载入和删除不需要的栏位两项。其它所谓更精细的优化,性能提升有限。

附录

实体类定义

 public class Author
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string Country { get; set; }
        public int BooksCount { get; set; }
        public string NickName { get; set; }

        [ForeignKey("UserId")]
        public User User { get; set; }
        public int UserId { get; set; }
        public virtual List<Book> Books { get; set; } = new List<Book>();
    }
 public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        [ForeignKey("AuthorId")]
        public Author Author { get; set; }
        public int AuthorId { get; set; }
        public DateTime Published { get; set; }
        public string ISBN { get; set; }
        [ForeignKey("PublisherId")]
        public Publisher Publisher { get; set; }
        public int PublisherId { get; set; }
    }
public class Publisher
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Established { get; set; }
    }
     public class User
    {
        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string UserName { get; set; }
        public string Email { get; set; }
        public virtual List<UserRole> UserRoles { get; set; } = new List<UserRole>();
        public DateTime Created { get; set; }
        public bool EmailConfirmed { get; set; }
        public DateTime LastActivity { get; set; }
    }
    public class Role
    {
        public int Id { get; set; }
        public virtual List<UserRole> UserRoles { get; set; } = new List<UserRole>();
        public string Name { get; set; }
    }

public  class AuthorWeb
 {
     public DateTime UserCreated { get; set; }
     public bool UserEmailConfirmed { get; set; }
     public string UserFirstName { get; set; }
     public DateTime UserLastActivity { get; set; }
     public string UserLastName { get; set; }
     public string UserEmail { get; set; }
     public string UserName { get; set; }
     public int UserId { get; set; }
     public int AuthorId { get; set; }
     public int Id { get; set; }
     public int RoleId { get; set; }
     public int BooksCount { get; set; }
     public List<BookWeb> AllBooks { get; set; }
     public int AuthorAge { get; set; }
     public string AuthorCountry { get; set; }
     public string AuthorNickName { get; set; }
 }
 public class BookWeb
 {
         public int Id { get; set; }
         public string Name { get; set; }
         public DateTime Published { get; set; }
         public int PublishedYear { get; set; }
         public string PublisherName { get; set; }
         public string ISBN { get; set; }
     
 }

优化方法

[Benchmark]
public  List<AuthorWeb> GetAuthors() {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                                 .Include(x => x.User)
                                 .ThenInclude(x => x.UserRoles)
                                 .ThenInclude(x => x.Role)
                                 .Include(x => x.Books)
                                 .ThenInclude(x => x.Publisher)
                                 .ToList()
                                 .Select(x => new AuthorWeb
                                 {
                                     UserCreated = x.User.Created,
                                     UserEmailConfirmed = x.User.EmailConfirmed,
                                     UserFirstName = x.User.FirstName,
                                     UserLastActivity = x.User.LastActivity,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                     UserId = x.User.Id,
                                     RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                         Id = y.Id,
                                         Name = y.Name,
                                         Published = y.Published,
                                         ISBN = y.ISBN,
                                         PublisherName = y.Publisher.Name
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     AuthorNickName = x.NickName,
                                     Id = x.Id
                                 })
                                 .ToList()
                                 .Where(x => x.AuthorCountry == "France" && x.AuthorAge >= 20)
                                 .ToList();

     var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in orderedAuthors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }

 [Benchmark]
 public List<AuthorWeb> GetAuthors_RemoveToList()
 {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                                 .Include(x => x.User)
                                 .ThenInclude(x => x.UserRoles)
                                 .ThenInclude(x => x.Role)
                                 .Include(x => x.Books)
                                 .ThenInclude(x => x.Publisher)
                               //  .ToList()
                                 .Select(x => new AuthorWeb
                                 {
                                     UserCreated = x.User.Created,
                                     UserEmailConfirmed = x.User.EmailConfirmed,
                                     UserFirstName = x.User.FirstName,
                                     UserLastActivity = x.User.LastActivity,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                     UserId = x.User.Id,
                                     RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                         Id = y.Id,
                                         Name = y.Name,
                                         Published = y.Published,
                                         ISBN = y.ISBN,
                                         PublisherName = y.Publisher.Name
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     AuthorNickName = x.NickName,
                                     Id = x.Id
                                 })
                                // .ToList()
                                 .Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
                                 .ToList();

     var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in orderedAuthors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }
 [Benchmark]
 public  List<AuthorWeb> GetAuthorsOptimized_RemoveColumn()
 {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                              //   .Include(x => x.User)
                                 //.ThenInclude(x => x.UserRoles)
                              //   .ThenInclude(x => x.Role)
                              //   .Include(x => x.Books)
                            //     .ThenInclude(x => x.Publisher)
                                 .Select(x => new AuthorWeb
                                 {
                                  //   UserCreated = x.User.Created,
                                   //  UserEmailConfirmed = x.User.EmailConfirmed,
                                     UserFirstName = x.User.FirstName,
                                  //   UserLastActivity = x.User.LastActivity,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                //     UserId = x.User.Id,
                                //     RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                     //    Id = y.Id,
                                         Name = y.Name,
                                         Published = y.Published,
                                  //       ISBN = y.ISBN,
                                //         PublisherName = y.Publisher.Name
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     AuthorNickName = x.NickName,
                                  //   Id = x.Id
                                 })
                                 .Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
                                 .ToList();

     var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().Take(2).ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in orderedAuthors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }

[Benchmark]
 public List<AuthorWeb> GetAuthorsOptimized_AsNoTracking()
 {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                                 .AsNoTracking()
                                 // .Include(x => x.User)
                                 //   .ThenInclude(x => x.UserRoles)
                                 //   .ThenInclude(x => x.Role)
                                 //    .Include(x => x.Books)
                                 //   .ThenInclude(x => x.Publisher)
                                 .Select(x => new AuthorWeb
                                 {
                                     //UserCreated = x.User.Created,
                                     //    UserEmailConfirmed = x.User.EmailConfirmed,
                                     UserFirstName = x.User.FirstName,
                                     // UserLastActivity = x.User.LastActivity,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                     //  UserId = x.User.Id,
                                     //RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                         // Id = y.Id,
                                         Name = y.Name,
                                         Published = y.Published,
                                         //ISBN = y.ISBN,
                                         //PublisherName = y.Publisher.Name
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     //AuthorNickName = x.NickName,
                                     Id = x.Id
                                 })
                                 .Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
                                 .ToList();

      var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in authors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }


 [Benchmark]
 public List<AuthorWeb> GetAuthorsOptimized_Take_Order()
 {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                                 .AsNoTracking()
                                 .Select(x => new AuthorWeb
                                 {
                                     UserFirstName = x.User.FirstName,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                         Name = y.Name,
                                         Published = y.Published,
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     AuthorNickName = x.NickName,
                                 })
                                 .Where(x => x.AuthorCountry == "France" && x.AuthorAge >=20)
                                 .OrderByDescending(x => x.BooksCount)
                                 .Take(2)
                                 .ToList();

    // var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in authors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }


 [Benchmark]
 public List<AuthorWeb> GetAuthorsOptimized_ChangeOrder()
 {
     using var dbContext = new AppDbContext();

     var authors = dbContext.Authors
                                  .AsNoTracking()
                                  .Where(x => x.Country == "France" && x.Age >=20)
                                  .OrderByDescending(x => x.BooksCount)
                                 // .Include(x => x.User)
                                 //   .ThenInclude(x => x.UserRoles)
                                 //   .ThenInclude(x => x.Role)
                                 //    .Include(x => x.Books)
                                 //   .ThenInclude(x => x.Publisher)
                                 .Select(x => new AuthorWeb
                                 {
                                     //UserCreated = x.User.Created,
                                     //    UserEmailConfirmed = x.User.EmailConfirmed,
                                     UserFirstName = x.User.FirstName,
                                     // UserLastActivity = x.User.LastActivity,
                                     UserLastName = x.User.LastName,
                                     UserEmail = x.User.Email,
                                     UserName = x.User.UserName,
                                     //  UserId = x.User.Id,
                                     //RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                     BooksCount = x.BooksCount,
                                     AllBooks = x.Books.Select(y => new BookWeb
                                     {
                                         // Id = y.Id,
                                         Name = y.Name,
                                         Published = y.Published,
                                         //ISBN = y.ISBN,
                                         //PublisherName = y.Publisher.Name
                                     }).ToList(),
                                     AuthorAge = x.Age,
                                     AuthorCountry = x.Country,
                                     //AuthorNickName = x.NickName,
                                     Id = x.Id
                                 })                                     
                                 .Take(2)
                                 .ToList();

     // var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();

     List<AuthorWeb> finalAuthors = new List<AuthorWeb>();
     foreach (var author in authors)
     {
         List<BookWeb> books = new List<BookWeb>();

         var allBooks = author.AllBooks;

         foreach (var book in allBooks)
         {
             if (book.Published.Year < 1900)
             {
                 book.PublishedYear = book.Published.Year;
                 books.Add(book);
             }
         }

         author.AllBooks = books;
         finalAuthors.Add(author);
     }

     return finalAuthors;
 }

//  [Benchmark]
 public List<AuthorWeb> GetAuthorsOptimized_IncludeFilter()
 {
     using var dbContext = new AppDbContext();
     var date = new DateTime(1900, 1, 1);
     var authors = dbContext.Authors
                                 .AsNoTracking()
                                 .Include(x => x.Books.Where(b => b.Published < date))
                                 .Include(x => x.User)
                                  // .IncludeFilter(x =>x.Books.Where(b =>b.Published.Year < 1900))
                                  .Where(x => x.Country == "France" && x.Age >=20)
                                  .OrderByDescending(x => x.BooksCount)
                              
                                 //   .ThenInclude(x => x.UserRoles)
                                 //   .ThenInclude(x => x.Role)
                                 //    .Include(x => x.Books)
                                 //   .ThenInclude(x => x.Publisher)
                                 .Take(2)
                                 .ToList();

     // var orderedAuthors = authors.OrderByDescending(x => x.BooksCount).ToList().ToList();

     var authorList = authors.AsEnumerable().Select(x => new AuthorWeb
     {
         //UserCreated = x.User.Created,
         //    UserEmailConfirmed = x.User.EmailConfirmed,
         UserFirstName = x.User.FirstName,
         // UserLastActivity = x.User.LastActivity,
         UserLastName = x.User.LastName,
         UserEmail = x.User.Email,
         UserName = x.User.UserName,
         //  UserId = x.User.Id,
         //RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
         BooksCount = x.BooksCount,
         AllBooks = x.Books
                                        //    .Where(b => b.Published < date)
                                        .Select(y => new BookWeb
                                        {
                                            // Id = y.Id,
                                            Name = y.Name,
                                            Published = y.Published,
                                            //ISBN = y.ISBN,
                                            //PublisherName = y.Publisher.Name
                                        }).ToList(),
         AuthorAge = x.Age,
         AuthorCountry = x.Country,
         //AuthorNickName = x.NickName,
         //    Id = x.Id
     }).ToList();

     return authorList;
 }


 [Benchmark]
 public List<AuthorWeb> GetAuthorsOptimized_SelectFilter()
 {
     using var dbContext = new AppDbContext();
     var date = new DateTime(1900, 1, 1);
     var authors = dbContext.Authors
                                 .AsNoTracking()
                                 .Include(x => x.Books.Where(b => b.Published < date))
                                 .Where(x => x.Country == "France" && x.Age >=20)
                                 .OrderByDescending(x => x.BooksCount)
                                 .Select(x => new AuthorWeb
                                  {
                                      //UserCreated = x.User.Created,
                                      //    UserEmailConfirmed = x.User.EmailConfirmed,
                                      UserFirstName = x.User.FirstName,
                                      // UserLastActivity = x.User.LastActivity,
                                      UserLastName = x.User.LastName,
                                      UserEmail = x.User.Email,
                                      UserName = x.User.UserName,
                                      //  UserId = x.User.Id,
                                      //RoleId = x.User.UserRoles.FirstOrDefault(y => y.UserId == x.UserId).RoleId,
                                      BooksCount = x.BooksCount,
                                      AllBooks = x.Books
                                         .Where(b => b.Published < date)
                                        .Select(y => new BookWeb
                                        {
                                            // Id = y.Id,
                                            Name = y.Name,
                                            Published = y.Published,
                                            //ISBN = y.ISBN,
                                            //PublisherName = y.Publisher.Name
                                        }).ToList(),
                                      AuthorAge = x.Age,
                                      AuthorCountry = x.Country,
                                      //AuthorNickName = x.NickName,
                                      //    Id = x.Id
                                  })
                                 .Take(2)
                                 .ToList();
     return authors;
 }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/107253.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TVRNet网络PyTorch实现

文章目录 文章地址网络各层结构代码实现 文章地址 An End-to-End Traffic Visibility Regression Algorithm文章通过训练搜集得到的真实道路图像数据集&#xff08;Actual Road dense image Dataset, ARD&#xff09;&#xff0c;通过专业的能见度计和多人标注&#xff0c;获得…

Qt QWebEngine 更换语言

背景 使用Qt QWebEngine开发的应用&#xff0c;在一些场景下&#xff0c;会显示英文文本&#xff0c;比如右键、JS弹出的对话框&#xff0c;所以需要进行汉化&#xff0c;更改语言。 准备翻译文件 Qt有提供翻译好的ts文件&#xff0c;我们可以直接下载ts文件qtwebengine_zh_…

世界前沿技术发展报告2023《世界航空技术发展报告》(二)军用飞机技术

&#xff08;二&#xff09;军用飞机技术 1.作战飞机1.1 美俄对第五代战斗机进行升级改进1.2 美欧第六代战斗机技术取得新进展1.3 美国B-21隐身轰炸机正式亮相 2.支援飞机2.1 美国空军拟研制翼身融合布局运输/加油机2.2 美欧厂商积极参加北约未来预警机技术研究项目2.3 美国空军…

1817_ChibiOS的RT线程

全部学习汇总&#xff1a; GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 1. 关于线程&#xff0c;有几个概念需要弄清楚&#xff1a;声明、生命循环、延迟、线程引用、线程队列、线程时间、优先级管理、调度。 2. 两个声明…

线性表的定义和基本操作

线性表的定义和基本操作 一、线性表的定义 线性表&#xff08;Linear List&#xff09;是具有相同数据类型的n(n>0)个数据元素的有限序列&#xff0c;其中n为表长&#xff0c;当n0时线性表是一个空表。若用L命名线性表&#xff0c;则其一般表示为 L (a1,a2,...,ai,ai1,.…

JMeter + Ant + Jenkins持续集成-接口自动化测试

需要安装的工具&#xff1a; jdk1.8jmeter3.2ant1.9jenkins2.1 1、Jdkwin7系统如何安装jdk及环境变量的配置-百度经验 安装包安装设置环境变量验证是否安装正确 Java -version检查&#xff0c;如下就代表安装成功了&#xff0c;环境变量设置就去搜索了&#xff0c;网上很多…

TimeGPT:时间序列预测的第一个基础模型

时间序列预测领域在最近的几年有着快速的发展&#xff0c;比如N-BEATS、N-HiTS、PatchTST和TimesNet。 大型语言模型(llm)最近在ChatGPT等应用程序中变得非常流行&#xff0c;因为它们可以适应各种各样的任务&#xff0c;而无需进一步的训练。 这就引出了一个问题:时间序列的…

File相关方法2

一.获取当前目录下所有一级文件名称 1.代码 package org.example;import java.io.File;public class day03 {public static void main(String[] args) {//获取当前目录下所有一级文件名称final File f1 new File("d:/temp");final String[] name f1.list();for (…

VDA到Excel方案介绍之自定义邮件接收主题

VDA标准是德国汽车工业协会&#xff08;Verband der Automobilindustrie&#xff0c;简称VDA&#xff09;制定的一系列汽车行业标准。这些标准包括了汽车生产、质量管理、供应链管理、环境保护、安全性能等方面的规范和指南。VDA标准通常被德国和国际上的汽车制造商采用&#x…

学习笔记:二分图

二分图 引入 二分图又被称为二部图。 二分图就是可以二分答案的图。 二分图是节点由两个集合组成&#xff0c;且两个集合内部没有边的图。换言之&#xff0c;存在一种方案&#xff0c;将节点划分成满足以上性质的两个集合。 性质 如果两个集合中的点分别染成黑色和白色&am…

目录和文件操作

在自己电脑任一盘符中新建以OS_Test命名的文件夹&#xff0c;并在该文件夹中新建新建3个以.txt&#xff0c;3个 .xlsx为扩展名的文件&#xff08;文件名由代码随机生成&#xff0c;长度为8&#xff0c;由字母数字组成&#xff09;。&#xff0c;请写一个程序&#xff0c;删除掉…

stm32的ADC采样率如何通过Time定时器进行控制

ADC采样率是个跟重要的概念. 手册上说可以通过Timer定时器进行触发ADC采样. 可我这边悲剧的是, 无论怎么样. ADC都会进行采样. 而且就算是TIM停掉也是一样会进行采样. 这就让我摸不着头脑了… 我想通过定时器动态更改ADC的采样频率. 结果不随我愿… 这到底是什么问题呢? 一…

el-table(vue2中)滚动条被固定列盖住

一、项目场景&#xff1a; vue2 el-table 二、问题描述 1、现场图片&#xff1a; 2、全局css环境配置了滚动条高度为6px /* 全局滚动条配置 */ ::-webkit-scrollbar {width: 6px;height: 6px; }::-webkit-scrollbar-track {background-color: #f1f1f1; }::-webkit-scrollbar-…

STM32 定时器配置不当导致误差(精度)偏大的问题发现与解决

通用定时器TIM2/3/4/5&#xff0c;PWM输出1Khz的波形 一开始初始化代码如下&#xff1a; void MX_TIM2_Init(void)//1kHz {TIM_ClockConfigTypeDef sClockSourceConfig {0};TIM_MasterConfigTypeDef sMasterConfig {0};TIM_OC_InitTypeDef sConfigOC {0};htim2.Instance T…

AI与Prompt:解锁软件开发团队的魔法咒语,在复杂任务上生成正确率更高的代码

AI与Prompt&#xff1a;解锁软件开发团队的魔法咒语 写在最前面论文&#xff1a;基于ChatGPT的自协作代码生成将团队协作理论应用于代码生成的研究自协作框架原理1、DOL任务分配2、共享黑板协作3、Instance实例化 案例说明简单任务&#xff1a;基本操作&#xff0c;生成的结果1…

【MySQL架构篇】逻辑架构

逻辑架构 文章目录 逻辑架构1. 服务器处理客户端请求2. Connectors3. 第一层&#xff1a;连接层4. 第二层&#xff1a;服务层5. 第三层&#xff1a;存储引擎6. 存储层7. 小结 1. 服务器处理客户端请求 首先 MySQL 是典型的 C/S 架构&#xff0c;即 Client/Server 架构&#xf…

Python深度学习实战-基于tensorflow原生代码搭建BP神经网络实现分类任务(附源码和实现效果)

实现功能 前面两篇文章分别介绍了两种搭建神经网络模型的方法&#xff0c;一种是基于tensorflow的keras框架&#xff0c;另一种是继承父类自定义class类&#xff0c;本篇文章将编写原生代码搭建BP神经网络。 实现代码 import tensorflow as tf from sklearn.datasets import…

在CentOS 7中手工打造和运行xml文件配置的Servlet,然后使用curl、浏览器、telnet等三种工具各自测试

下载Openjdk并配置环境变量 https://jdk.java.net/java-se-ri/11-MR2是官网下载Openjdk 11的地方。 sudo wget https://download.java.net/openjdk/jdk11.0.0.1/ri/openjdk-11.0.0.1_linux-x64_bin.tar.gz下载openjdk 11。 sudo mkdir -p /usr/openjdk11创建目录&#xff…

一张图系列 - “kv cache“

我觉得回答这个问题需要知道3个知识点&#xff1a; 1、multi-head-attention是如何计算的&#xff1f;attention的数学公式&#xff1f; kv cache是如何存储和传递的&#xff1f; 2、kv cache 的原理步骤是什么&#xff1f;为什么降低了消耗&#xff1f; 3、kv cache 代码模…

C++:stl中set(multiset)和map(multimap)的介绍和使用

本文主要从概念、常用接口和使用方法方面介绍set(multiset)和map(multimap)。 目录 一、概念介绍 1.关联式容器 2.键值对 3. 树形结构的关联式容器 二、set和multiset 1.set的介绍 2.set使用 1. set模板参数列表 2. set构造 3. set迭代器 4. set容量 5. set修改操…