2009-12-08 12 views
7

Die folgende LINQ Aussage:Warum erhält diese LINQ-zu-SQL-Abfrage eine NotSupportedException?

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 
     return (from t in db.Tasks 
       where searchTerms.All(term => 
        t.Title.ToUpper().Contains(term.ToUpper()) && 
        t.Description.ToUpper().Contains(term.ToUpper())) 
       select t).Cast<Item>().ToList(); 
    } 
} 

gibt mir diese Fehler:

System.NotSupportedException: Lokale Sequenz nicht in LINQ verwendet werden kann Implementierung von Abfrageoperatoren außer auf SQL der Operator Contains().

drum herum Blick scheint meine einzige Option alle meine Artikel erste in eine generische Liste zu bekommen, dann eine LINQ-Abfrage auf das tun.

Oder gibt es eine clevere Möglichkeit, die obige LINQ-to-SQL-Anweisung umzuformulieren, um den Fehler zu vermeiden?

ANTWORT:

Dank Randy, Ihre Idee hat mir geholfen, die folgende Lösung zu erstellen. Es ist nicht elegant, aber es löst das Problem und da dies Code generiert wird, kann ich bis zu z. 20 Suchbegriffe ohne zusätzliche Arbeit:

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 

     switch (searchTerms.Count()) 
     { 
      case 1: 
       return (db.Tasks 
        .Where(t => 
         t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0]) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      case 2: 
       return (db.Tasks 
        .Where(t => 
         (t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0])) 
         && 
         (t.Title.Contains(searchTerms[1]) 
         || t.Description.Contains(searchTerms[1])) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      case 3: 
       return (db.Tasks 
        .Where(t => 
         (t.Title.Contains(searchTerms[0]) 
         || t.Description.Contains(searchTerms[0])) 
         && 
         (t.Title.Contains(searchTerms[1]) 
         || t.Description.Contains(searchTerms[1])) 
         && 
         (t.Title.Contains(searchTerms[2]) 
         || t.Description.Contains(searchTerms[2])) 
         ) 
        .Select(t => t)).Cast<Item>().ToList(); 
      default: 
       return null; 
     } 
    } 
} 
+0

Beachten Sie, dass dies kein Fehler "nicht implementiert" ist, es ist ein Fehler "lokale Sequenz kann nicht verwendet werden". – Lucas

+0

danke, behoben, dass –

+0

Ich bin mir nicht sicher, ob ich das richtig lese, es ist eine Menge Klammern, aber ich sehe keine gut gebildete Where-Klausel. Ihre searchTerms.All() gibt eine Liste von Zeichenfolgen zurück, die keine where-Klausel bilden, daher der Fehler. – Lazarus

Antwort

1

Ed, ich bin in eine ähnliche Situation geraten. Der Code ist unten. Die wichtige Codezeile ist, wo ich die Variable memberList gesetzt habe. Sehen Sie, ob das zu Ihrer Situation passt. Entschuldigung, wenn die Formatierung nicht gut herausgekommen ist.

Randy

// Get all the members that have an ActiveDirectorySecurityId matching one in the list. 
IEnumerable<Member> members = database.Members 
    .Where(member => activeDirectoryIds.Contains(member.ActiveDirectorySecurityId)) 
    .Select(member => member); 

// This is necessary to avoid getting a "Queries with local collections are not supported" 
//error in the next query.  
memberList = members.ToList<Member>(); 

// Now get all the roles associated with the members retrieved in the first step. 
IEnumerable<Role> roles = from i in database.MemberRoles 
    where memberList.Contains(i.Member) 
    select i.Role; 
+0

Sorry Randy, aber Sie haben den Punkt hier verpasst. – Lazarus

1

Da Sie nicht lokale Sequenz mit Linq Tisch sitzen können, ist der einzige Weg, um die obige Abfrage in SQL zu übersetzen woluld erstellen seine WHERE-Klausel mit so vielen LIKE-Bedingungen, da es Elemente in search Liste (verkettet mit UND-Operatoren). Scheinbar macht linq das nicht automatisch und löst stattdessen eine expection aus. Aber es kann durch Iteration durch die Sequenz manuell erfolgen:

public override List<Item> SearchListWithSearchPhrase(string searchPhrase) 
{ 
    List<string> searchTerms = StringHelpers.GetSearchTerms(searchPhrase); 

    using (var db = Datasource.GetContext()) 
    { 
     IQueryable<Task> taskQuery = db.Tasks.AsQueryable(); 
     foreach(var term in searchTerms) 
     { 
       taskQuery = taskQuery.Where(t=>t.Title.ToUpper().Contains(term.ToUpper()) && t.Description.ToUpper().Contains(term.ToUpper()))    
     } 
     return taskQuery.ToList(); 
    } 
} 

, dass sich die Abfrage noch ausgeführt wird durch DBMS als einer SQL-Anweisung. Der einzige Nachteil ist, dass die searchTerms-Liste nicht zu lang sein sollte - andernfalls würde die erzeugte SQL-Anweisung nicht effizient sein.

+0

das sieht gut aus, aber ich kann es nicht zum arbeiten bringen, ich bekomme immer: Argument Datentyp Text ist ungültig für Argument 1 der oberen Funktion. –

+0

Wenn Ihre Datenbankspalten Titel und Beschreibung den Text TEXT enthalten, werden die meisten Operatoren CONTAINS ('like') und wahrscheinlich TOUPPER nicht funktionieren. TEXT-Spalten sollten mit dem Volltextsuchindex und gespeicherten Prozeduren anstelle von linq abgefragt werden. Verwenden Sie also entweder FTS (http: // msdn.microsoft.com/en-us/library/ms142571.aspx) oder ändern Sie die Spalten von TEXT in NVARCHAR (MAX). (Ich spreche über SQL Server) – PanJanek

Verwandte Themen