EF Core Where Clause выдает исключение при сравнении даты с datenow - PullRequest
0 голосов
/ 11 октября 2019

У меня есть метод Query, который должен дать мне следующие матчи с сегодняшней даты до 7 дней, учитывая идентификатор лиги. Так что, если сегодняшняя дата 2019-10-11, то она должна дать мне все спортивные матчи до 2019-10-18.

        public IQueryable<MatchDTO> GetMatchesForNextSevenDaysByLeagueAsync(int leagueId)
        {
            var todayDate = DateTime.Now;
            var matches = _context.Matches.Include(e => e.HomeTeam).Include(e => e.AwayTeam).Include(e => e.League).Where(m => m.LeagueId == leagueId).OrderBy(m => m.MatchDate).ThenBy(m => m.Time).Where(m => ((todayDate - m.MatchDate).Days) <=7).Select(m => DTOConverter.ConvertMatchToDTO(m));

            return matches;
        }

Вызов вызывает исключение:

"The LINQ expression 'Where<Match>(\r\n    source: 
ThenBy<Match, DateTime>(\r\n        source: OrderBy<Match, DateTime>(\r\n            
source: Where<Match>(\r\n                source: DbSet<Match>, \r\n                
predicate: (m) => m.LeagueId == (Unhandled parameter: __leagueId_0)), \r\n            
keySelector: (m) => m.MatchDate), \r\n        keySelector: (m) => m.Time), \r\n    
predicate: (m) => m.MatchDate - (Unhandled parameter: __todayDate_1).TotalDays <= 7)' 
could not be translated. Either rewrite the query in a form that can be translated, or 
switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), 
ToList(), or ToListAsync(). 
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."

Мне кажется, мне не нравится, как я сравниваю даты в .Where(m => ((todayDate - m.MatchDate).Days) <=7)

Iпытался использовать оценку клиента, но это слишком медленно. Любые мысли о том, как я могу переписать это, чтобы код работал.

Обратите внимание, что я использую EF Core 3.0

1 Ответ

0 голосов
/ 11 октября 2019

Так что эту строку немного сложно прочитать без прокрутки назад и вперед, поэтому я надеюсь, что вы не возражаете, что я переформатировал ее для моего собственного согласия:

var matches = _context
    .Matches
    .Include(e => e.HomeTeam)
    .Include(e => e.AwayTeam)
    .Include(e => e.League)
    .AsQueryable()
    .Where(m => m.LeagueId == leagueId)
    .OrderBy(m => m.MatchDate)
    .ThenBy(m => m.Time)
    .Where(m => ((todayDate - m.MatchDate).Days) <=7)
    .Select(m => DTOConverter.ConvertMatchToDTO(m));

Чтение через этоЯ вижу, что ваше второе предложение .Where проверяет значение свойства .Days одной даты минус другая. Я сомневаюсь, что Entity Framework способна перевести это в действительный SQL, поэтому вы видите эту ошибку.

Есть ли причина, по которой вы не можете рассчитать на клиенте, какая дата является "допустимой", а затем простоSQL фильтрует строки по необходимости? Например:

.Where(m => m.MatchDate >= DateTime.Now && <= DateTime.Now.AddDays(7))

Это должно быть переведено в оператор TSQL BETWEEN - что гораздо лучше, чем попытка проанализировать время, которое вы сохранили, чтобы получить часть дня и работуесли они на конкретное число от заданной даты.

Тем не менее, вы, возможно, захотите взглянуть на запрос, который вы написали в целом. Я не совсем уверен из предоставленного вами фрагмента, почему .AsQueryable необходим - методы расширения, которые вы используете, принимают как IEnumerable, так и IQueryable, поэтому вам не нужно приводить.

Я бы также объединил два предложения where перед попыткой упорядочить набор результатов. Не уверен, что EF to SQL достаточно умен во всех случаях, чтобы оптимизировать это, но это не повредит! В итоге ваш окончательный запрос должен выглядеть примерно так:

var matches = _context
    .Matches
    .Include(e => e.HomeTeam)
    .Include(e => e.AwayTeam)
    .Include(e => e.League)
    .Where(m => 
        m.LeagueId == leagueId 
        && m.MatchDate >= DateTime.Now && <= DateTime.Now.AddDays(7))
    .OrderBy(m => m.MatchDate)
    .ThenBy(m => m.Time)
    .Select(m => DTOConverter.ConvertMatchToDTO(m));
...