3

悪いタイトルで申し訳ありません...これはおそらく例で説明するのが一番です:

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.

前もって感謝します。

4

1 に答える 1

3

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、2回目の試行で、EFはtoLinkToクエリを事前に個別に実行して(クエリにを追加するかのようにAsEnumerable())、最初にメモリ内にオブジェクトのコレクションを作成します。queryToExecute@mellamokbの回答で説明されているように、はこのコレクションでは機能しません。最初の試行では、クエリは全体として実行され、問題は発生しません。

queryToExecute22番目の例の新しい変数を作成すると、両方の例が機能します。

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がツリーを評価する方法に関係していますが、何が起こっているのかを実際に理解または説明することは私の視野を超えています。

編集

2回目の試行でまったく同じクエリを使用しても、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();
于 2012-04-04T16:03:41.800 に答える