Не удалось преобразовать ошибку EF Core 3, OrderByDescending и ThenBy rerurn

#linq #entity-framework-core #entity-framework-core-3.1

#linq #entity-framework-core #entity-framework-core-3.1

Вопрос:

  • EF Core 3.1.8
  • Npgsql.EntityFrameworkCore.PostgreSQL 3.1.4

Я реализовал следующий запрос, который должен удалить всю группу комментариев по дате и времени.

 var commentsOnPage = await _repository.GetAll()
                .OrderByDescending(c => c.Date.Date)
                .ThenBy(c => c.Date.TimeOfDay)
                .Skip(pageSize * pageIndex)
                .Take(pageSize)
                .ToListAsync();



 public class CommentRepository : GenericRepository<Comment>, ICommentRepository
    {
        private readonly AppDbContext _dbContext;

        public CommentRepository(AppDbContext dbContext) : base(dbContext)
        {
            _dbContext = dbContext;
        }

        public IQueryable<Comment> GetAll() => ((AppDbContext)_dbContext).Comments.AsQueryable();

    }
  

Ошибка возврата:

 An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The LINQ expression 'DbSet<Comment>
    .OrderByDescending(c => c.Date.Date)
    .ThenBy(c => c.Date.TimeOfDay)' could not be translated. 
  

Ответ №1:

Одним из текущих дефектов перевода запросов ядра EF является отсутствие документации о том, что поддерживается. Чтобы усложнить ситуацию, поставщикам баз данных разрешено добавлять переводы к некоторым свойствам / методам CLR, которые они решают, поэтому даже если какой-либо запрос LINQ преобразуется для одного поставщика базы данных, он может завершиться ошибкой для другого.

В данном конкретном случае неподдерживаемый элемент является TimeOfDay . Поставщик SQLServer поддерживает это, но Npgsql этого не делает. По крайней мере, Npgsql предоставил документацию для поддерживаемых переводов, которая показывает, что TimeOfDay отсутствует (не поддерживается).

С другой стороны, Npgsql DateTime поддерживает оператор вычитания (но SQLServer этого не делает), поэтому одним из способов решения проблемы для Npgsql является вычисление TimeOfDay путем вычитания части даты из значения datetime

 .ThenBy(c => c.Date - c.Date.Date)
  

Другой способ, который позволил бы достичь цели для этого конкретного случая (и должен работать с любым поставщиком), — это просто использовать значение datetime

 .ThenBy(c => c.Date)
  

Это потому ThenBy , что действует только для равных значений в OrderBy . Поскольку вы сначала упорядочиваете по дате (без времени), то для равных дат вы можете просто упорядочить по дате и времени, что будет иметь тот же эффект, что и время суток.