Сравнение части даты OffsetDateTime с сегодняшним днем в EF/Linq с помощью NodaTime

#entity-framework #linq #asp.net-core #nodatime

Вопрос:

Я использую ASP.NET ядро 3.1. Я пытаюсь получить список завершенных сегодня сеансов.

Я могу восстановить все сеансы, которые закончились таким образом:

 var zonedClock = SystemClock.Instance.InTzdbSystemDefaultZone();
OffsetDateTime now = zonedClock.GetCurrentOffsetDateTime();

return _context.Session
.Where(x => (Local.Compare(x.EndDateTime, now) <0))
.Include(o => o.Tournaments)
.ToList<Session>();
 

где EndDateTime — это время смещения NodaTime, а Local-время смещения.Comparer. Однако, когда я пытаюсь также сопоставить дату, как это:

 return _context.Session
.Where(x => (Local.Compare(x.EndDateTime, now) <0)
 amp;amp; x.StartDateTime.Date.Equals(now.Date))
.Include(o => o.Tournaments)
.ToList<Session>();
 

Я получаю следующую ошибку:

 InvalidOperationException: The LINQ expression 'DbSet<Session>()
.LeftJoin(
inner: DbSet<Venue>(),
outerKeySelector: s => EF.Property<Nullable<int>>(s, "VenueId"),
innerKeySelector: v => EF.Property<Nullable<int>>(v, "VenueId"),
resultSelector: (o, i) => new TransparentIdentifier<Session, Venue>(
Outer = o,
Inner = i
))
.Where(s => __Local_0.Compare(
x: s.Outer.EndDateTime,
y: __now_1) >= 0 amp;amp; s.Outer.StartDateTime.Date.Equals(__now_Date_2) amp;amp; s.Inner == __Venue_3 amp;amp; s.Outer.Lane == __Lane_4)' 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 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|15_0(ShapedQueryExpression translated, ref <>c__DisplayClass15_0 )
 

добавление.AsEnumerable (), похоже, не помогает.

Есть какие-нибудь идеи?

Комментарии:

1. Где вы пытались добавить AsEnumerable()? Я определенно ожидал бы, что это поможет с точки зрения изменения сравнения, которое будет выполняться в процессе, а не в базе данных.

2. (Хотя использование Include(o => o.Tournaments) может быть проблемой здесь.)

3. Возможно, вам захочется сначала разработать способ выполнения «возможно, слишком широкого» фильтра в базе данных, а затем более точного для результатов в памяти.

4. Если я помещу его перед включением, он откажется компилироваться, так что это как раз перед этим . ТоЛист

5. Я думаю Local.Compare , что это невозможно перевести на SQL.

Ответ №1:

Я решил эту проблему. Необходимо включить таблицу турниров в начале, а затем использовать .Как бесчисленное множество до этого .Где затем генерировать экземпляры компаратора из статики, например:

 return  _context.Session
            .Include(o => o.Tournaments)
            .AsEnumerable()
            .Where(x => (OffsetDateTime.Comparer.Local.Compare(x.EndDateTime, now) <0)
             amp;amp; x.StartDateTime.Date.Equals(now.Date))
            .ToList<Session>();
 

Комментарии:

1. Это обходной путь. Вся таблица с подробностями загружается в память.

2. да, это неоптимально