Указанный член типа Date не поддерживается в исключении LINQ to Entities.

105

У меня возникло исключение при выполнении следующих утверждений.

 DateTime result;
 if (!DateTime.TryParse(rule.data, out result))
     return jobdescriptions;
 if (result < new DateTime(1754, 1, 1)) // sql can't handle dates before 1-1-1753
     return jobdescriptions;
 return jobdescriptions.Where(j => j.JobDeadline.Date == Convert.ToDateTime(rule.data).Date );

Исключение

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Я знаю, что означает исключение, но не знаю, как от него избавиться. Любая помощь?

туманность
источник
Это в EF6 и ниже. EF core поддерживает .Date.
Герт Арнольд

Ответы:

102

LINQ to Entities не может транслировать большинство методов .NET Date (включая используемое приведение) в SQL, поскольку не существует эквивалентного SQL.

Решение состоит в том, чтобы использовать методы Date вне оператора LINQ, а затем передать значение. Похоже, что Convert.ToDateTime (rule.data) .Date вызывает ошибку.

Дата вызова свойства DateTime также не может быть преобразована в SQL, поэтому обходной путь заключается в сравнении свойств .Year .Month и .Day, которые можно преобразовать в LINQ, поскольку они являются только целыми числами.

var ruleDate = Convert.ToDateTime(rule.data).Date;
return jobdescriptions.Where(j => j.Deadline.Year == ruleDate.Year 
                       && j.Deadline.Month == ruleDate.Month 
                       && j.Deadline.Day == ruleDate.Day);
Дзюдо
источник
6
А как насчет j => j.JobDeadline.Date?
nebula
1
Является ли Date свойством JobDeadline? Само по себе это не должно вызывать ошибку - возможно, конфликт имен (но не уверен в этом). Если строка все еще вызывает ошибку, просто переименуйте ее в DeadlineDate или подобное.
Дзюдо
1
Дата - это свойство JobDeadline. JobDeadline - это тип DateTime, из которого я хочу извлечь Date.
nebula
Затем, чтобы работать с этим в LINQ, вам нужно просто сравнить свойство JobDeadline, например j.JobDeadline> ruleDate. Это требует небольшого тестирования, но может работать. Или сравните три свойства .Month .Day и .Year (j.Deadline.Year == ruleDate.Year && j j.Deadline.Month == ruleDate.Month && j.Deadline.Day == ruleDate.Day). Не элегантно, но работает, поскольку это только целые числа.
Дзюдо
Хм. Эта идея работает. Грязно, но работает. Если вы напишете это как ответ, я могу отметить его правильным.
nebula
230

Вы можете использовать метод TruncateTime EntityFunctions, чтобы добиться правильного перевода Dateсвойства в SQL:

using System.Data.Objects; // you need this namespace for EntityFunctions

// ...

DateTime ruleData = Convert.ToDateTime(rule.data).Date;
return jobdescriptions
    .Where(j => EntityFunctions.TruncateTime(j.JobDeadline) == ruleData);


Обновление: EntityFunctions устарело в EF6, используйтеDbFunctions.TruncateTime

Slauma
источник
Я заметил, что ruleDataэто DateTimeтип и j.JobDeadlineусеченное время. Не кажется правильным. Не было исключения, но и ожидаемого результата не было.
nebula
@aneal: возвращает все записи JobDeadlineс той же датой, что и rule.data, независимо от времени суток . Разве это не то, чего вы хотите достичь с помощью вашего вопроса в вопросе? Почему это не так?
Slauma
1
+1, и я согласен с вышеизложенным, это определенно лучший ответ для 99% реализаций,
Джим Толлан
26
Обратите внимание, что EntityFunctionsв EF6 это не рекомендуется, теперь вы должны использовать DbFunctions.
Julien N
2
Пространство имен для функций DbFunctions в> EF6 System.Data.Entity: msdn.microsoft.com/en-us/library/Dn220142(v=VS.113).aspx
GraehamF
39

Для EF6 используйте вместо этого DbFunctions.TruncateTime (mydate).

Король Гипокритов
источник
9

«EntityFunctions.TruncateTime» или «DbFunctions.TruncateTime» в ef6 работает, но у него есть проблемы с производительностью в больших данных.

Я думаю, что лучше всего поступить так:

DateTime ruleDate = Convert.ToDateTime(rule.data);

DateTime  startDate = SearchDate.Date;

DateTime  endDate = SearchDate.Date.AddDay(1);

return jobdescriptions.Where(j.Deadline >= startDate 
                       && j.Deadline < endDate );

это лучше, чем использовать части даты до. потому что запрос выполняется быстрее в больших данных.

Махди Шахбази
источник
+1 за этот ответ. EntityFunctions.TruncateTime(позже заменены на DbFunctions.TruncateTime) реализуются путем преобразования в SQL, где datetime преобразуется в строку и усекается. Это значительно замедляет выполнение запроса пропорционально количеству обработанных записей.
urig
3

Нужно включить using System.Data.Entity;. Хорошо работает даже сProjectTo<>

var ruleDate = rule.data.Date;
return jobdescriptions.Where(j => DbFunctions.TruncateTime(j.Deadline) == ruleDate);
Омкар
источник
Как уже был дан здесь
Герт Арнольд
1

Это означает, что LINQ to SQL не знает, как Dateпреобразовать свойство в выражение SQL. Это связано с тем, что Dateсвойство DateTimeструктуры не имеет аналога в SQL.

Адам Робинсон
источник
1

У меня это сработало.

DateTime dt = DateTime.Now.Date;
var ord = db.Orders.Where
      (p => p.UserID == User && p.ValidityExpiry <= dt);

Источник: Форумы Asp.net

MRT2017
источник
0

У меня такая же проблема, но я работаю с DateTime-Ranges. Мое решение - настроить время начала (с любой датой) на 00:00:00 и время окончания на 23:59:59. Так что мне больше не нужно преобразовывать DateTime в Date, вместо этого он остается DateTime.

Если у вас есть только один DateTime, вы также можете установить время начала (с любой датой) на 00:00:00 и время окончания на 23:59:59. Затем вы выполняете поиск, как если бы это был промежуток времени.

var from = this.setStartTime(yourDateTime);
var to = this.setEndTime(yourDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);

Вы также можете сделать это с помощью DateTime-Range:

var from = this.setStartTime(yourStartDateTime);
var to = this.setEndTime(yourEndDateTime);

yourFilter = yourFilter.And(f => f.YourDateTime.Value >= from && f.YourDateTime.Value <= to);
Питер70
источник
0

вы можете получить Enum как:

DateTime todayDate = DateTime.Now.Date; var check = db.tableName.AsEnumerable().Select(x => new
        {
            Date = x.TodayDate.Date
        }).Where(x => x.Date == todayDate).FirstOrDefault();
Омид Сулейман
источник
Это эффективно перечисляет все содержимое таблицы заранее, чтобы применить фильтр даты ... кажется потенциально очень плохой идеей!
Хавьер Рапопорт
0

Как здесь многие отмечали, использование функции TruncateTime происходит медленно.

Самый простой вариант - использовать EF Core. Он может это сделать. Если вы не можете, то лучшей альтернативой усечению будет вообще не изменять запрашиваемое поле, а изменять границы. Если вы выполняете обычный запрос типа «между», в котором нижняя и верхняя границы не являются обязательными, следующее поможет.

    public Expression<Func<PurchaseOrder, bool>> GetDateFilter(DateTime? StartDate, DateTime? EndDate)
    {
        var dtMinDate = (StartDate ?? SqlDateTime.MinValue.Value).Date;
        var dtMaxDate = (EndDate == null || EndDate.Value == SqlDateTime.MaxValue.Value) ? SqlDateTime.MaxValue.Value : EndDate.Value.Date.AddDays(1);
        return x => x.PoDate != null && x.PoDate.Value >= dtMinDate && x.PoDate.Value < dtMaxDate;
    }

По сути, вместо того, чтобы обрезать PoDate только до части Date, мы увеличиваем верхнюю границу запроса и user <вместо <=

статлер
источник