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()