对不好的标题感到抱歉......最好用一个例子解释这个:
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 :(得分: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();