Ошибка свойства DateTime в предложении LINQ where - PullRequest
5 голосов
/ 21 апреля 2019

У меня есть довольно простой метод, который использует некоторые LINQ для доступа к данным в моей базе данных.

У меня есть некоторые элементы, в которых хранится дата их создания.Даты включают смещение, поэтому оно хранится как тип datetimeoffset в БД.Я пытаюсь отфильтровать элементы по дате, и для этого мне нужно вычесть смещение часов, чтобы сравнить их:

public async Task<IEnumerable<Item>> GetItems(DateTime? startDate)
{
    var items = _dbContext.Items                                
                        .AsQueryable();

    if (startDate != null)
    {
        items = items.Where(i =>
            i.DateCreated.DateTime.AddHours(i.DateCreated.Offset.Hours) >= startDate.Value);
    }

    return await items
                     .ToListAsync();
}

Но когда вызывается ToListAsync(), я получаю эту ошибку:

Ошибка, сгенерированная для предупреждения 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: выражение LINQ' где ([e] .DateCreated.DateTime.AddHours (Convert ([e] .DateCreated.Offset.Hours, Double))> = __startDate_Value_0) 'не удалось перевести и будет оцениваться локально.'.Это исключение можно подавить или зарегистрировать, передав идентификатор события «RelationalEventId.QueryClientEvaluationWarning» методу «ConfigureWarnings» в «DbContext.OnConfiguring» или «AddDbContext».

Похоже, проблема связана с AddHours метод, если я возьму это, он работает просто отлично.Но я не знаю, есть ли способ заставить это работать без использования этого метода.

Есть ли другая стратегия, которую я могу использовать здесь?

Ответы [ 2 ]

4 голосов
/ 21 апреля 2019

Обновленный ответ (EF Core):

Согласно эта ссылка , DbFunctions в настоящее время не поддерживается в EF Core.

Если вы хотите вызвать AddHour с помощью EF Core, один из вариантов - определить AddHour как скалярную функцию в вашей БД, а затем вызвать ее в своем запросе LINQ.

Этот документ объясняет, как это можно сделать:

Объявите статический метод в вашем DbContext и аннотируйте его с помощью DbFunctionAttribute:

public class MyDbContext : DbContext
{
    [DbFunction]
    public static int AddHours(DataTime source, int hours)
    {
        // don't need any implementation
        throw new Exception();
    }
}

Подобные методы автоматически регистрируются. После регистрации вызовы метода в запросе LINQ могут быть преобразованы в вызовы функций в SQL:

items = items.Where(i =>
    MyDbContext.AddHours(i.DateCreated, i.DateCreated.Offset.Hours) >= startDate.Value);

Оригинальный ответ (EF 4/5/6):

AddHour не является функцией в вашей БД. Его необходимо преобразовать в соответствующую функцию в БД.

Если вы используете SQL Server, вы можете использовать этот код, который переведет AddHour в соответствующую функцию БД:

items = items.Where(i =>
    DbFunctions.AddHour(i.DateCreated, i.DateCreated.Offset.Hours) >= startDate.Value);

Если вы не используете SQL Server, вам нужно определить функцию AddHour в вашей БД, после определения которой вы можете использовать DbFunctions.AddHour для ее вызова.

3 голосов
/ 22 апреля 2019

На самом деле перевод DateTime.AddHours метода поддерживается .

Проблема в том, что в настоящее время EF Core не может перевести большинство (если не все) членов DateTimeOffset, в данном конкретном случае - свойство DateTime (то же самое для Offset, DateTimeUtc и т. Д.).

К счастью, поддерживает поддержку перевода DateTimeOffset сравнений, поэтому решение состоит в том, чтобы сделать это иначе - преобразовать параметры DateTime в DateTimeOffset и выполнить простые сравнения внутри запроса, например:

if (startDate != null)
{
    // Note: must be a variable outside the query expression tree
    var startDateOffset = new DateTimeOffset(startDate.Value);
    items = items.Where(i => i.DateCreated >= startDateOffset);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...