2012-04-04 44 views
2

很抱歉的坏称号......这一个可能是最好的例子来解释:实体框架:不能使用“包含”与另一个对象属性

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

如何来时toLinkTo是这个工程在本地声明,但使用完全相同的IQueryable作为另一个对象上的属性不?我得到的唯一的例外是:提前

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

感谢。

+0

这'leafNodesWithExternalChildren'实际上应该是'queryToExecute',对不对? – Slauma 2012-04-04 15:30:56

回答

2

你的第二个例子工程太 - 如果你把它的第一个例子:

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,在第二次尝试EF执行toLinkTo查询前期和单独(好像是把一个AsEnumerable()追加到查询)首先在内存中创建一个对象集合。 queryToExecute不适用于这个集合 - 正如@ mellamokb的回答中所解释的。在第一次尝试中,查询将作为一个整体执行并且不会发生问题。如果你创建了第二个例子中新queryToExecute2变量

两个例子都工作:

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

它可能如何为queryToExecute表达式树建做的方式以及它如何使用局部变量toLinkTo或者EF如何评估这棵树,但是真正理解或解释到底发生了什么,这超出了我的视野。

编辑

即使使用完全相同的toLinkTo相同的查询第二次尝试不起作用:

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

就我所做的例子而言,你是对的。我的实际代码仍然失败,所以在LINQPad中使用它之后,看起来差别是直接在查询中使用'OtherClass.LinkedClassA',或者在使用它之前将其分配给局部变量。 – Ocelot20 2012-04-04 16:34:31