我正在将一些东西从一个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()'方法,并且此方法无法转换为商店 表达
任何人都知道为什么会这样吗?
答案 0 :(得分:133)
只需将字符串保存到临时变量,然后在表达式中使用它:
var strItem = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == strItem
select p;
问题出现是因为ToString()
没有真正执行,它变成MethodGroup然后解析并转换为SQL。由于没有ToString()
等价物,表达式失败。
请务必查看Alex's answer关于稍后添加的SqlFunctions
帮助程序类的信息。在许多情况下,它可以消除对临时变量的需求。
答案 1 :(得分:65)
正如其他人已经回答的那样,这会破坏,因为.ToString在进入数据库的途中无法转换为相关的SQL。
但是,Microsoft提供了SqlFunctions class,它是可以在这种情况下使用的方法集合。
对于这种情况,您在这里寻找的是SqlFunctions.StringConvert:
from p in context.pages
where p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
select p;
当出于某种原因不适合使用临时变量的解决方案时,这是好的。
与SqlFunctions类似,您还有EntityFunctions(EF6已被DbFunctions废弃),它提供了一组不同的函数,这些函数也与数据源无关(不限于SQL)。
答案 2 :(得分:23)
问题是您在LINQ to Entities查询中调用ToString。这意味着解析器正在尝试将ToString调用转换为其等效的SQL(这是不可能的......因此异常)。
您所要做的就是将ToString调用移到单独的一行:
var keyString = item.Key.ToString();
var pages = from p in context.entities
where p.Serial == keyString
select p;
答案 3 :(得分:10)
有类似的问题。 通过调用实体集合上的ToList()并查询列表来解决它。 如果集合很小,这是一个选项。
IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())
希望这有帮助。
答案 4 :(得分:6)
像这样改变它应该有效:
var key = item.Key.ToString();
IQueryable<entity> pages = from p in context.pages
where p.Serial == key
select p;
在LINQ查询被声明但在foreach
的行中没有抛出异常的原因是延迟执行功能,即在您尝试访问结果之前不执行LINQ查询。这发生在foreach
而不是更早。
答案 5 :(得分:3)
将表转换为Enumerable
,然后使用ToString()
方法调用LINQ方法:
var example = contex.table_name.AsEnumerable()
.Select(x => new {Date = x.date.ToString("M/d/yyyy")...)
但是在调用AsEnumerable
或ToList
方法时要小心,因为在此方法之前您将请求来自所有实体的所有数据。在上面的例子中,我通过一个请求读取了所有table_name
行。
答案 6 :(得分:2)
升级到实体框架版本6.2.0 为我工作。
我之前使用过6.0.0版。
希望这有帮助,
答案 7 :(得分:1)
在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);
}
}
答案 8 :(得分:0)
如果您确实要在查询中输入ToString
,可以编写一个表达式树访问者,使用call to the appropriate StringConvert
function重写对ToString
的调用:
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);
}
}
}
答案 9 :(得分:0)
在这种情况下我得到了同样的错误:
|| log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search)
花了太多时间调试后,我发现错误出现在逻辑表达式中。
第一行CAST
确实可以正常工作,但是处理DateTime对象的最后一行使它失败了:
CONVERT
删除有问题的行并解决问题。
我不完全理解为什么,但似乎ToString()是字符串的LINQ表达式,但不是实体。 LINQ for Entities处理SQL等数据库查询,而SQL没有ToString()的概念。因此,我们不能将ToString()抛出到.Where()子句中。
但是第一行如何运作呢? SQL有Tuple = Struct.new(:_1, :_2)
2.2.5 :003 > t = Tuple.new("a", "b")
=> #<struct Tuple _1="a", _2="b">
2.2.5 :004 > t._1
=> "a"
2.2.5 :005 > t._2
=> "b"
和2.2.5 :012 > a, b = t
=> {:_1=>"a", :_2=>"b"}
2.2.5 :013 > a
=> {:_1=>"a", :_2=>"b"}
2.2.5 :014 > b
=> nil
,而不是ToString(),所以到目前为止我最好的猜测是实体的linq在一些简单的情况下使用它。 DateTime对象并不总是那么简单......
答案 10 :(得分:-7)
只要您需要在LINQ查询中使用方法调用,只需将LINQ to Entity查询转换为LINQ to Objects查询(例如,调用ToArray)。