LINQ to Entities не распознает метод DateTime.ToLocalTime()

Я занимаюсь разработкой сайта MVC. В одном из представлений мне нужно использовать:

return View(db.Logs
    .OrderByDescending(l => l.Date)
    .Where(l => ((DateTime)l.Date).ToLocalTime().ToString().Contains(search) 
            || l.Name.Contains(search))
    .ToList()
    .ToPagedList(pageNumber, pageSize));

Но я получаю эту ошибку:

LINQ to Entities не распознает метод метода System.DateTime ToLocalTime(), и этот метод нельзя преобразовать в выражение хранилища.

Мне нужно преобразовать l.Date toLocalTime, а затем сравнить с search

Как мне это сделать?

4 ответа

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

Как указывал Раш Фрисби, если вы пошли по этому пути, то вам действительно нужно рассмотреть хранимую процедуру.

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

Я, вероятно, буду опущен, потому что это на самом деле не отвечает на прямой вопрос, НО я думаю, что лучший ответ на ваш вопрос - это изменение общей архитектуры логики поиска.

1) нормализуйте свой Date данные столбца, так что все строки в Logs имеют один и тот же часовой пояс. Лучший вариант, потому что вам не нужно выполнять преобразование в запросе, которое сделает запрос быстрее, а также по другим причинам, например, для облегчения чтения отчетов.

2) Используйте sproc или параметризованный запрос, в который вы конвертируете Date используя функцию SQL TODATETIMEOFFSET(<date>,<offset>)

3) Если вы хотите преобразовать его пост-запросом, вы должны вызвать ToList() для запроса, чтобы он извлекал данные, а затем преобразовать дату в местный часовой пояс:

var data = db.Logs.OrderByDescending(l => l.Date)
.Where(l => ((DateTime)l.Date).ToString().Contains(search) 
|| l.Name.Contains(search))
.Skip((pageNumber-1)*pageSize).Take(pageSize)
.ToList(); //ToList() causes the query to execute

//now you can convert the Date
foreach (var item in data)
{
    item.Date = item.Date.ToLocalTime();
}

return View(data);

Вы также должны использовать Skip а также Take в запросе вместо ToPagedList так что вы не вытягиваете ВСЕ данные.

4) В вашем View (не в Controller) вы можете вызывать ToLocalTime при отображении переменной... (при условии Razor) @Model.Date.ToLocalTime()

Однако вы должны помнить, что ToLocalTime собирается преобразовать дату в местное время, на которое настроен ваш сервер, а не в местное время пользователя, просматривающего веб-страницу. Если вы хотите сделать это, вам нужно либо получить их часовой пояс из заголовков запроса или через javascript и передать его вместе с запросом, а затем использовать это значение для форматирования даты, прежде чем она будет передана обратно в представление - или просто выполнить это преобразование. на стороне клиента с использованием JavaScript.

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

В качестве альтернативы вы можете преобразовать свой поисковый фильтр в формат времени данных, поступающий из базы данных, а не пытаться преобразовать его в LocalTime.

Вы не можете вызвать метод ToLocalTime внутри выражения, так как EF не знает, как преобразовать его в оператор SQL. Проверьте SqlFunctions, когда вы получите такого рода исключения, и попытайтесь найти любой подходящий метод для ваших целей.

Также рассмотрите возможность сохранения этих дат по местному времени. Или вместо сравнения с поиском сравните его с чем-то вроде var dateSearchCriteroa = searchCriteria.ToNotLocal()

Другие вопросы по тегам