实体框架:不能在另一个对象上使用“包含”属性

时间:2012-04-04 15:08:13

标签: .net linq entity-framework linq-to-entities ef-code-first

对不好的标题感到抱歉......最好用一个例子解释这个:

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.

提前致谢。

1 个答案:

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