LINQ to Entities non riconosce il metodo ‘System.String ToString ()’ e questo metodo non può essere tradotto in un’espressione di archivio

Sto migrando alcune cose da un server mysql a un server SQL ma non riesco a capire come far funzionare questo codice:

using (var context = new Context()) { ... foreach (var item in collection) { IQueryable 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(); } 

Quando entra nella seconda foreach (var page in pages) lancia un’eccezione dicendo:

LINQ to Entities non riconosce il metodo ‘System.String ToString ()’ e questo metodo non può essere tradotto in un’espressione di archivio.

Qualcuno sa perché questo succede?

Basta salvare la stringa in una variabile temporanea e quindi usarla nella tua espressione:

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

Il problema sorge perché ToString() non è realmente eseguito, viene trasformato in un MethodGroup e quindi analizzato e tradotto in SQL. Poiché non esiste alcun ToString() equivalente, l’espressione fallisce.

Nota:

Assicurati di controllare anche la risposta di Alex relativa alla class helper SqlFunctions che è stata aggiunta in seguito. In molti casi può eliminare la necessità della variabile temporanea.

Come altri hanno risposto, questo si interrompe perché. ToString non riesce a tradurre in SQL pertinente sulla strada verso il database.

Tuttavia, Microsoft fornisce la class SqlFunctions che è una raccolta di metodi che possono essere utilizzati in situazioni come questa.

Per questo caso, quello che stai cercando è SqlFunctions.StringConvert :

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

Buono quando la soluzione con variabili temporanee non è desiderabile per qualsiasi motivo.

Simile a SqlFunctions si hanno anche le EntityFunctions (con EF6 reso obsoleto da DbFunctions ) che fornisce un diverso insieme di funzioni che sono anche agnostiche di origine dati (non limitate ad esempio ad SQL).

Il problema è che si chiama ToString in una query LINQ to Entities. Ciò significa che il parser sta tentando di convertire la chiamata ToString nel suo equivalente SQL (che non è ansible … quindi l’eccezione).

Tutto quello che devi fare è spostare la chiamata ToString su una linea separata:

 var keyString = item.Key.ToString(); var pages = from p in context.entities where p.Serial == keyString select p; 

Aveva un problema simile. Risolto il problema chiamando ToList () sulla raccolta di quadro e interrogando l’elenco. Se la collezione è piccola, questa è un’opzione.

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

Spero che questo ti aiuti.

Cambialo in questo modo e dovrebbe funzionare:

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

Il motivo per cui l’eccezione non viene generata nella riga viene dichiarata la query LINQ ma nella riga del foreach è la funzione di esecuzione differita, ovvero la query LINQ non viene eseguita finché non si tenta di accedere al risultato. E questo succede nel foreach e non prima.

Trasmetti tabella a Enumerable , quindi chiami i metodi LINQ con il metodo ToString() all’interno:

  var example = contex.table_name.AsEnumerable() .Select(x => new {Date = x.date.ToString("M/d/yyyy")...) 

Ma fai attenzione quando ToList metodi AsEnumerable o ToList perché richiedi tutti i dati di tutte le quadro prima di questo metodo. Nel mio caso sopra ho letto tutte le righe table_name di una richiesta.

Se si desidera digitare ToString all’interno della query, è ansible scrivere un visitatore dell’albero dell’espressione che riscriva la chiamata a ToString con una chiamata alla funzione StringConvert appropriata :

 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> 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); } } } 

In MVC, supponi di cercare i record in base alle tue esigenze o informazioni. Funziona correttamente.

 [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 emplist = employeeContext.Employees.Where(x => x.Gender == value).ToList(); return View("Index", emplist); } else { List emplist = employeeContext.Employees.Where(x => x.Name == value).ToList(); return View("Index", emplist); } } 

L’aggiornamento a Entity Framework versione 6.2.0 ha funzionato per me.

Ero precedentemente sulla versione 6.0.0.

Spero che questo ti aiuti,

Ho avuto lo stesso errore in questo caso:

 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); 

Dopo aver speso troppo tempo nel debug, ho capito che l’errore appariva nell’espressione logica.

La prima riga search.Contains(log.Id.ToString()) funziona bene, ma l’ultima riga che si occupa di un object DateTime lo ha fatto fallire miseramente:

 || log.Timestamp.ToString(CultureInfo.CurrentUICulture).Contains(search) 

Rimuovi la linea problematica e il problema risolto.

Non capisco perfettamente il motivo, ma sembra che ToString () sia un’espressione LINQ per le stringhe, ma non per le Entità. LINQ per Entities si occupa di query di database come SQL e SQL non ha alcuna nozione di ToString (). Pertanto, non possiamo lanciare ToString () in una clausola .Where ().

Ma come funziona allora la prima linea? Invece di ToString (), SQL ha CAST e CONVERT , quindi la mia ipotesi migliore è che linq per quadro lo usi in alcuni casi semplici. Gli oggetti DateTime non sono sempre stati trovati così semplici …

È sufficiente trasformare la query LINQ in Entity in una query LINQ to Objects (ad es. Chiamare ToArray) ogni volta che è necessario utilizzare una chiamata di metodo nella query LINQ.