LINQ to Entities无法识别方法'System.String ToString()'方法,并且此方法无法转换为存储表达式

时间:2011-05-05 14:45:43

标签: c# mysql sql linq

我正在将一些东西从一个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 个答案:

答案 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")...)

但是在调用AsEnumerableToList方法时要小心,因为在此方法之前您将请求来自所有实体的所有数据。在上面的例子中,我通过一个请求读取了所有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)。