我正在将一些东西从一个mysql服务器迁移到一个sql server但我无法弄清楚如何使这个代码工作:
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()'方法,并且此方法无法转换为存储表达式 .
谁知道为什么会这样?
11 回答
只需将字符串保存到临时变量,然后在表达式中使用它:
问题出现是因为
ToString()
没有真正执行,它变成MethodGroup然后解析并转换为SQL . 由于没有ToString()
等效,表达式失败 .注意:
请确保您还查看Alex's answer,了解稍后添加的
SqlFunctions
帮助程序类 . 在许多情况下,它可以消除对临时变量的需求 .正如其他人已经回答的那样,这会因为.ToString在进入数据库的途中无法转换为相关的SQL而中断 .
但是,Microsoft提供了SqlFunctions class,它是可以在这种情况下使用的方法集合 .
在这种情况下,您在这里寻找的是SqlFunctions.StringConvert:
当具有临时变量的解决方案因任何原因而不可取时是好的 .
与SqlFunction类似,您还有EntityFunctions(EF6已被DbFunctions淘汰),它提供了一组不同的函数,这些函数也是数据源不可知的(不限于例如SQL) .
问题是您在LINQ to Entities查询中调用ToString . 这意味着解析器正在尝试将ToString调用转换为其等效的SQL(这是不可能的......因此异常) .
您所要做的就是将ToString调用移到单独的行:
有类似的问题 . 通过调用实体集合上的ToList()并查询列表来解决它 . 如果集合很小,这是一个选项 .
希望这可以帮助 .
像这样改变它应该工作:
在LINQ查询声明但在
foreach
行中没有抛出异常的原因是延迟执行功能,即在您尝试访问结果之前不会执行LINQ查询 . 这发生在foreach
而不是更早 .将表转换为
Enumerable
,然后使用ToString()
方法调用LINQ方法:但是在调用
AsEnumerable
或ToList
方法时要小心,因为在此方法之前您将请求来自所有实体的所有数据 . 在上面的例子中,我通过一个请求读取了所有table_name
行 .升级到 Entity Framework Version 6.2.0 为我工作 .
我以前的版本是6.0.0 .
希望这可以帮助,
在MVC中,假设您正在根据您的要求或信息搜索记录 . 它运作正常 .
如果你真的想在查询中输入
ToString
,你可以编写一个表达式树访问者,用call to the appropriate StringConvert function重写对ToString
的调用:在这种情况下我得到了同样的错误:
花了太多时间调试后,我发现错误出现在逻辑表达式中 .
第一行
search.Contains(log.Id.ToString())
确实工作正常,但是处理DateTime对象的最后一行使它失败了:Remove the problematic line and problem solved.
我不完全理解为什么,但似乎ToString()是字符串的LINQ表达式,但不是实体 . LINQ for Entities处理SQL等数据库查询,而SQL没有ToString()的概念 . 因此,我们不能将ToString()抛出到.Where()子句中 .
但是第一行如何运作呢?而不是ToString(),SQL有
CAST
和CONVERT
,所以到目前为止我最好的猜测是实体的linq在一些简单的情况下使用它 . DateTime对象并不总是那么简单......只需在LINQ查询中使用方法调用时,只需将LINQ to Entity查询转换为LINQ to Objects查询(例如,调用ToArray) .