LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression

后端 未结 11 2031
花落未央
花落未央 2020-11-22 10:41

I\'m migrating some stuff from one mysql server to a sql server but i can\'t figure out how to make this code work:

using (var context = new Context())
{
            


        
相关标签:
11条回答
  • 2020-11-22 11:06

    Had a similar problem. Solved it by calling ToList() on the entity collection and querying the list. If the collection is small this is an option.

    IQueryable<entity> pages = context.pages.ToList().Where(p=>p.serial == item.Key.ToString())
    

    Hope this helps.

    0 讨论(0)
  • 2020-11-22 11:07

    Just save the string to a temp variable and then use that in your expression:

    var strItem = item.Key.ToString();
    
    IQueryable<entity> pages = from p in context.pages
                               where  p.Serial == strItem
                               select p;
    

    The problem arises because ToString() isn't really executed, it is turned into a MethodGroup and then parsed and translated to SQL. Since there is no ToString() equivalent, the expression fails.

    Note:

    Make sure you also check out Alex's answer regarding the SqlFunctions helper class that was added later. In many cases it can eliminate the need for the temporary variable.

    0 讨论(0)
  • 2020-11-22 11:13

    Change it like this and it should work:

    var key = item.Key.ToString();
    IQueryable<entity> pages = from p in context.pages
                               where  p.Serial == key
                               select p;
    

    The reason why the exception is not thrown in the line the LINQ query is declared but in the line of the foreach is the deferred execution feature, i.e. the LINQ query is not executed until you try to access the result. And this happens in the foreach and not earlier.

    0 讨论(0)
  • 2020-11-22 11:13

    In MVC, assume you are searching record(s) based on your requirement or information. It is working properly.

    [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);
        }         
    }
    
    0 讨论(0)
  • 2020-11-22 11:17

    If you really want to type ToString inside your query, you could write an expression tree visitor that rewrites the call to ToString with a call to the appropriate StringConvert function:

    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);
    
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 11:21

    As others have answered, this breaks because .ToString fails to translate to relevant SQL on the way into the database.

    However, Microsoft provides the SqlFunctions class that is a collection of methods that can be used in situations like this.

    For this case, what you are looking for here is SqlFunctions.StringConvert:

    from p in context.pages
    where  p.Serial == SqlFunctions.StringConvert((double)item.Key.Id)
    select p;
    

    Good when the solution with temporary variables is not desirable for whatever reasons.

    Similar to SqlFunctions you also have the EntityFunctions (with EF6 obsoleted by DbFunctions) that provides a different set of functions that also are data source agnostic (not limited to e.g. SQL).

    0 讨论(0)
提交回复
热议问题