2012-04-04 21 views
2

Sorry für die schlechte Titel ... Dieser ist wahrscheinlich mit einem Beispiel am besten erklärt:Entity Framework: Kann nicht „Enthält“ mit Eigenschaft auf ein anderes Objekt verwenden

void Main() 
{ 
    IQueryable<ClassA> toLinkTo = context.ClassAs.Where(a => a.Name == "SomeName"); 

    var queryToExecute = context.ClassBs.Where(cb => toLinkTo.Select(ca => ca.Id).Contains(cb.Id)); 

    // This works. 
    leafNodesWithExternalChildren.ToList(); 

    // This doesn't work. 
    toLinkTo = new OtherClass(context).LinkedClassAs; 
    leafNodesWithExternalChildren.ToList(); 
} 

public class OtherClass 
{ 
    private MyContext m_Context; 

    public OtherClass(MyContext ctx) 
    { 
     this.m_Context = ctx; 
    } 

    public IQueryable<ClassA> LinkedClassAs 
    { 
     get 
     { 
      // Same as toLinkTo as it was originally declared above. 
      return this.m_Context.ClassAs.Where(a => a.Name == "SomeName"); 
     } 
    } 
} 

Wie kommt das funktioniert, wenn toLinkTo ist lokal deklariert, aber mit der gleichen IQueryable als eine Eigenschaft auf ein anderes Objekt nicht? Die Ausnahme, die ich bekommen ist:

Unable to create a constant value of type 'ClassA'. Only primitive types ('such as Int32, String, and Guid') are supported.

Vielen Dank im Voraus.

+0

Dieses 'leafNodesWithExternalChildren' sollte eigentlich' queryToExecute', nicht wahr? – Slauma

Antwort

2

Ihr zweites Beispiel funktioniert auch - wenn Sie es das erste Beispiel machen:

IQueryable<ClassA> toLinkTo = new OtherClass(context).LinkedClassAs; 
var queryToExecute = context.ClassBs.Where(cb => toLinkTo.Select(ca => ca.Id) 
                 .Contains(cb.Id)); 

// Now, this works. 
queryToExecute.ToList(); 

// Now, this doesn't work. 
toLinkTo = context.ClassAs.Where(a => a.Name == "SomeName"); 
queryToExecute.ToList(); 

Somwhow, im zweiten Versuch EF führt die toLinkTo Abfrage im Voraus und separat (als ob es eine AsEnumerable() auf die Abfrage anhängen würde) um zuerst eine Sammlung von Objekten im Speicher zu erstellen. Die queryToExecute funktioniert nicht mit dieser Sammlung - wie in @ Mellamokb's Antwort erklärt. Beim ersten Versuch wird die Abfrage als Ganzes ausgeführt und das Problem tritt nicht auf.

Beiden Beispiele funktionieren, wenn Sie ein neues queryToExecute2 Variable für das zweite Beispiel erstellen:

IQueryable<ClassA> toLinkTo = context.ClassAs.Where(a => a.Name == "SomeName"); 
var queryToExecute = context.ClassBs.Where(cb => toLinkTo.Select(ca => ca.Id) 
                 .Contains(cb.Id)); 

// this works. 
queryToExecute.ToList(); 

// And this works too. 
toLinkTo = new OtherClass(context).LinkedClassAs; 
var queryToExecute2 = context.ClassBs.Where(cb => toLinkTo.Select(ca => ca.Id) 
                  .Contains(cb.Id)); 
queryToExecute2.ToList(); 

Es hat wahrscheinlich mit der Art und Weise, wie der Ausdrucksbaum für queryToExecute zu tun aufgebaut ist und wie es verwendet die lokale Variable toLinkTo oder wie EF den Baum bewertet, aber es ist jenseits meines Horizonts, um wirklich zu verstehen oder zu erklären, was genau vor sich geht.

bearbeiten

Auch wenn Sie verwenden, um genau die gleiche Abfrage für toLinkTo der zweite Versuch nicht funktioniert:

IQueryable<ClassA> toLinkTo = context.ClassAs.Where(a => a.Name == "SomeName"); 
var queryToExecute = context.ClassBs.Where(cb => toLinkTo.Select(ca => ca.Id) 
                 .Contains(cb.Id)); 

// this works. 
queryToExecute.ToList(); 

// this doesn't work. 
toLinkTo = context.ClassAs.Where(a => a.Name == "SomeName"); 
queryToExecute.ToList(); 
+0

Sie haben recht, soweit mein erfundenes Beispiel geht. Mein tatsächlicher Code versagte immer noch, also scheint es nach dem Spielen in LINQPad, dass der Unterschied "OtherClass.LinkedClassA" direkt in der Abfrage verwendet oder es einer lokalen Variablen zuweist, bevor es verwendet wird. – Ocelot20

Verwandte Themen