EF Core ошибка с запросом с группировкой и Count()

Нужно получить последний елемент с групп, группируя по нескольким полям. Используя эту кверю:

using(var context = new EFCoreDemoContext())
{
    IQueryable<Book> query = context.Books.GroupBy(x => new { x.Year, x.Month })
        .Select(y => y.OrderByDescending(z => z.Date ).FirstOrDefault());
     //it's ok
    var data = query.ToArray()
    //it's System.InvalidOperationException: 'Nullable object must have a value. exception here
    var count = query.Count();
}

Получаю ошибку "System.InvalidOperationException: 'Nullable object must have a value.'". Использую Net 6 + "Microsoft.EntityFrameworkCore" Version="6.0.6".

Что странно, кверя работает ок с query.ToArray()

Есть идеи?

Минимальный пример:

using Microsoft.EntityFrameworkCore;

Console.WriteLine("Start");

using(var context = new EFCoreDemoContext())
{
    IQueryable<Book> query = context.Books.GroupBy(x => new { x.Year, x.Month })
        .Select(y => y.OrderByDescending(z => z.Date ).FirstOrDefault());

    var count = query.Count();
}
Console.WriteLine("End");

public class EFCoreDemoContext : DbContext
{
    public DbSet<Book> Books { get; set; }
    public DbSet<Author> Authors { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=.\;Database=EFCoreDemo;Trusted_Connection=True;MultipleActiveResultSets=true");
    }
}

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }

    public DateTime Date { get; set; }

    public int Year { get; set; }

    public int Month { get; set; }

    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

public class Author
{
    public int AuthorId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<Book> Books { get; set; } = new List<Book>();
}

Ответы (1 шт):

Автор решения: Alexander Petrov

Поведение запроса с GroupBy соответствует спецификации.
Когда к первоначальному запросу применяется вызов Count() провайдер не понимает, что ему делать с теми данными, которые получаются в Select. Ведь они не используются в Count.

Я не совсем понимаю проблему.
Нужно получить общее количество сгрупированных данных - хорошо, получаем его первым запросом.
Потом нужно получить сами данные с определённой страницы - хорошо, получаем их вторым запросом. Материализуем в массив.

var query = context.Books.GroupBy(x => new { x.Year, x.Month });

IQueryable<Book> pagedQuery = query
    //.OrderBy(x => x.Key.Year)
    .Skip(10).Take(10)
    .Select(y => y.OrderByDescending(z => z.Date).FirstOrDefault());

var count = query.Count();
var array = pagedQuery.ToArray();

Можно включить логирование запросов, добавив в метод OnConfiguring следующую строку:

optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

Это позволит легко экспериментировать и отлаживать запросы.
В частности, выдаётся подсказка, что при использовании методов Take/Skip крайне желательно использовать OrderBy.

→ Ссылка