LINQ to Entities не распознает метод "System.String ToString()", и этот метод не может быть переведен в выражение хранилища
Я переношу некоторые вещи с одного сервера mysql на сервер sql, но я не могу понять, как заставить этот код работать:
using (var context = new Context())
{
...
foreach (var item in collection)
{
IQueryable<entity> pages = from p in context.pages
where p.Serial == item.Key.ToString()
select p;
foreach (var page in pages)
{
DataManager.AddPageToDocument(page, item.Value);
}
}
Console.WriteLine("Done!");
Console.Read();
}
Когда он входит во второй foreach (var page in pages)
, он выдает исключение:
LINQ to Entities не распознает метод 'System.String ToString() ', и этот метод не может быть переведен в хранилище выражение.
Кто-нибудь знает, почему это происходит?
Ответы
Ответ 1
Просто сохраните строку в переменной temp, а затем используйте ее в своем выражении:
var strItem = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == strItem
select p;
Проблема возникает из-за того, что ToString()
на самом деле не выполняется, она превращается в MethodGroup, а затем анализируется и переводится на SQL. Поскольку эквивалент ToString()
отсутствует, выражение терпит неудачу.
Примечание:
Убедитесь, что вы также проверили ответ Alex относительно вспомогательного класса SqlFunctions
, который был добавлен позже. Во многих случаях это может устранить необходимость в временной переменной.
Ответ 2
Как и другие ответили, это ломается, потому что .ToString не может перевести на соответствующий SQL по пути в базу данных.
Однако Microsoft предоставляет класс SqlFunctions, который представляет собой набор методов, которые можно использовать в таких ситуациях.
В этом случае вы здесь SqlFunctions.StringConvert:
from p in context.pages
where p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
select p;
Хорошо, когда решение с временными переменными нежелательно по каким-либо причинам.
Подобно SqlFunctions, вы также имеете EntityFunctions (с EF6, устаревшим DbFunctions), который предоставляет другой набор функций, которые также являются агностиками источника данных (не ограничиваясь, например, SQL).
Ответ 3
Проблема заключается в том, что вы вызываете ToString в запросе LINQ to Entities. Это означает, что синтаксический анализатор пытается преобразовать вызов ToString в его эквивалентный SQL (что невозможно... отсюда исключение).
Все, что вам нужно сделать, - переместить вызов ToString в отдельную строку:
var keyString = item.Key.ToString();
var pages = from p in context.entities
where p.Serial == keyString
select p;
Ответ 4
Была аналогичная проблема.
Решил его, вызвав ToList() в коллекции сущностей и запросив список.
Если коллекция небольшая, это вариант.
IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())
Надеюсь, что это поможет.
Ответ 5
Измените его так, и он должен работать:
var key = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == key
select p;
Причина, по которой исключение не выбрано в строке, объявленной запросом LINQ, но в строке foreach
есть функция отложенного выполнения, то есть запрос LINQ не выполняется до тех пор, пока вы не попытаетесь получить доступ к результату. И это происходит в foreach
и не раньше.
Ответ 6
Переведите таблицу в Enumerable
, затем вызовите методы LINQ с помощью метода ToString()
внутри:
var example = contex.table_name.AsEnumerable()
.Select(x => new {Date = x.date.ToString("M/d/yyyy")...)
Но будьте осторожны, когда вы вызываете методы AsEnumerable
или ToList
, потому что вы будете запрашивать все данные из всей сущности перед этим методом. В моем случае выше я прочитал все строки table_name
по одному запросу.
Ответ 7
Обновление до Entity Framework версии 6.2.0 сработало для меня.
Я был ранее на версии 6.0.0.
Надеюсь это поможет,
Ответ 8
В MVC предположите, что вы ищете запись (записи) на основе вашего требования или информации.
Он работает правильно.
[HttpPost]
[ActionName("Index")]
public ActionResult SearchRecord(FormCollection formcollection)
{
EmployeeContext employeeContext = new EmployeeContext();
string searchby=formcollection["SearchBy"];
string value=formcollection["Value"];
if (formcollection["SearchBy"] == "Gender")
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Gender == value).ToList();
return View("Index", emplist);
}
else
{
List<MvcApplication1.Models.Employee> emplist = employeeContext.Employees.Where(x => x.Name == value).ToList();
return View("Index", emplist);
}
}
Ответ 9
Если вы действительно хотите ввести ToString
внутри своего запроса, вы можете написать посетителю дерева выражений, который переписывает вызов ToString
с вызовом к соответствующему StringConvert
функция:
using System.Linq;
using System.Data.Entity.SqlServer;
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
using System;
namespace ToStringRewriting {
class ToStringRewriter : ExpressionVisitor {
static MethodInfo stringConvertMethodInfo = typeof(SqlFunctions).GetMethods()
.Single(x => x.Name == "StringConvert" && x.GetParameters()[0].ParameterType == typeof(decimal?));
protected override Expression VisitMethodCall(MethodCallExpression node) {
var method = node.Method;
if (method.Name=="ToString") {
if (node.Object.GetType() == typeof(string)) { return node.Object; }
node = Call(stringConvertMethodInfo, Convert(node.Object, typeof(decimal?));
}
return base.VisitMethodCall(node);
}
}
class Person {
string Name { get; set; }
long SocialSecurityNumber { get; set; }
}
class Program {
void Main() {
Expression<Func<Person, Boolean>> expr = x => x.ToString().Length > 1;
var rewriter = new ToStringRewriter();
var finalExpression = rewriter.Visit(expr);
var dcx = new MyDataContext();
var query = dcx.Persons.Where(finalExpression);
}
}
}
Ответ 10
В этом случае я получил ту же ошибку:
var result = Db.SystemLog
.Where(log =>
eventTypeValues.Contains(log.EventType)
&& (
search.Contains(log.Id.ToString())
|| log.Message.Contains(search)
|| log.PayLoad.Contains(search)
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
)
)
.OrderByDescending(log => log.Id)
.Select(r => r);
Проведя слишком много времени на отладку, я понял, что ошибка появилась в логическом выражении.
Первая строка search.Contains(log.Id.ToString())
работает нормально, но последняя строка, связанная с объектом DateTime, заставляла его терпеть неудачу:
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
Удалите проблемную линию и проблему.
Я не совсем понимаю, почему, но кажется, что ToString() является выражением LINQ для строк, но не для Entities. LINQ для Entities имеет дело с запросами базы данных, такими как SQL, и SQL не имеет понятия ToString(). Таким образом, мы не можем перетащить ToString() в предложение .Where().
Но как же работает первая строка? Вместо ToString() SQL имеет CAST
и CONVERT
, поэтому я догадываюсь, что linq для сущностей использует это в некоторых простых случаях. Объекты DateTime не всегда оказываются настолько простыми...
Ответ 11
Просто поверните запрос LINQ to Entity в запрос LINQ to Objects (например, вызовите ToArray) в любое время, когда вам нужно использовать вызов метода в запросе LINQ.