2009-06-04 6 views
0

Können Sie erklären, warum Beispiel # 1 mit "Keine Übersetzung in SQL" fehlschlägt und Beispiel # 2 funktioniert gut?LINQ: Keine Übersetzung nach SQL

Alle in Repository:

EX # 1:

public DomainPerson GetBestPerson() 
{  
     var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault(); 
     return person; 
} 

public IQueryable<DomainPerson> GetPeople() 
{ 
     var people= from p in Data.Persons 
        select MapToDomain(p); 

     return people; 
} 

private DomainPerson MapToDomain(Data.Person dataPerson) 
{ 
     DomainPerson domainPerson= new DomainPerson{ 
            Id=dataPerson.Id, 
            Name=dataPerson.Name, 
            Quality=dataPerson.Quality, 
            }; 
     return domainPerson; 
} 

EX # 2

public DomainPerson GetBestPerson() 
{  
     var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault(); 
     return person; 
} 

public IQueryable<DomainPerson> GetPeople() 
{ 
     var people= from p in Data.Persons 
        select new DomainPerson{ 
        Id=dataPerson.Id, 
        Name=dataPerson.Name, 
        Quality=dataPerson.Quality, 
        }; 


     return people; 
} 

Antwort

1

In der ersten, der Baum-Expression durch GetPeople hergestellt() enthält MapToDomain, das nicht in einen SQL-Ausdruck konvertiert werden kann.

Ändern Sie MapToDomain so, dass es ein IQueryable <> (* zurückgibt und die verbleibenden Aufrufe an MapToDomain() repariert, damit sie SingleOrDefault() aufrufen. Leichter erledigt als erklärt, kompiliert habe ich das nicht, da ich das nicht habe darunter liegende Objekte zur Verfügung:

public DomainPerson GetBestPerson() 
    {  
      var person= GetPeople().Where(p=>p.Quality=="Best").SingleOrDefault(); 
      return person; 
    } 

    public IQueryable<DomainPerson> GetPeople() 
    { 
      return MapToDomain(Data.Persons); 
    } 

    IQueryable<DomainPerson> MapToDomain(IQueryable<Person> persons) 
    { 
     return persons.select(dataPerson => new DomainPerson{ 
             Id=dataPerson.Id, 
             Name=dataPerson.Name, 
             Quality=dataPerson.Quality, 
             }; 
    } 
+0

Das ist völlig falsch. das würde die resultierende Abfrage zu einem IQueryable > machen, was überhaupt keinen Sinn ergibt. – kastermester

+0

Ja, ich vermisse einige Schritte in meiner Erklärung, fügte Code zur Klarstellung hinzu –

1

der Grund ist LINQ to SQL arbeitet durch das übersetzen Ausdruck Bäume (Expression<Func<T>>) zu SQL und es auf dem Server ausgeführt Verfahren Sie Referenzierung in # 1 auf IL zusammengestellt nach unten. LINQ to SQL kann eine Ausdrucksbaumdarstellung von seinem Körper nicht erfassen

Das zweite Beispiel ist nicht wirklich auf IL kompiliert. Es wird in Daten gespeichert, die zur Laufzeit gelesen und übersetzt werden können. My answer for this question erklärt dies im Detail.

+0

Ich glaube, der tatsächliche Name des Typs ist Ausdruck (nicht ExpressionTree ) - zumindest habe ich noch nie von ExpressionTree gehört kastermester

+0

Vielen Dank für die Kenntnisnahme. –

0

Es ist kontraintuitiv, dass der DomainPerson-Konstruktor übersetzt werden kann, während die MapToDomain-Methode nicht sein kann.

Vielleicht gibt es mehr zu der Geschichte als der Code, der gezeigt wird. Es gibt einen Syntaxfehler im zweiten Beispiel hier:

wählen neuen DomainPerson {

Ist das wirklich ein anonymer Typ in dem eigentlichen Code?

1

Wie andere erwähnt haben, hat es mit dem Code zu tun, mit dem LINQ To SQL arbeitet.

Sie müssen es ein bisschen so betrachten. In Ihrem ersten Beispiel - wenn wir die Ausdrücke betrachten (dh den Ausdrucksbaum), die GetPeople erzeugen wird - in menschlichen Worten erzeugt es einen Baum, der spezifiziert, dass wir aus unserer Tabelle auswählen - und dann die Funktion MapToDomain über jede Zeile in dieser Tabelle anwenden was passiert, ein Objekt des Typs DomainPerson zurückgeben.

Im zweiten Beispiel wissen wir nicht nur, dass der zurückkommende Typ DomainPerson ist - wir können auch sehen, welche Felder zu welchen Eigenschaften (und noch wichtiger wie) zugeordnet werden. Das bedeutet, dass wenn Sie später Ihre Where und Referenz p.Quality ausführen, Linq To SQL diese in die SQL-Tabelle zurückverfolgen kann und weiß, dass DomainPerson.Quality der Spalte Qualität in der Tabelle Personen zugeordnet ist.

Es ist ein wenig seltsam auf den ersten Blick, warum das erste Beispiel nicht funktioniert - aber Ihre MapToDomain Modell annehmen, sah aus wie so:

public void DomainPerson MapToDomain(Data.Person person){ 
    return new DomainPerson { 
     Quality = person.Quality + " Quality"; 
     //mode code here 
    }; 
} 

Nun, wie ist LINQ dieses „besondere“ wissen sollte, um SQL Kartierung? - Die Antwort ist einfach - kann es nicht.

Um es einfach auszudrücken - wenn Sie irgendetwas in Ihrer Select-Anweisung tun und Ihr Ergebnis projizieren möchten, muss die eigentliche Projektion als "Inline" -Code erfolgen (ich bin mir nicht sicher, was genau dafür der Begriff ist). wenn Sie danach mehr Abfragen (dh Sortieren, Filtern, usw.) durchführen möchten - sonst hat die Abfrage-Engine keine Chance in der Welt zu wissen, wie Ihr Mapping funktioniert.