「ステートメント本体を持つラムダ式は式ツリーに変換できません」


181

EntityFrameworkを使用A lambda expression with a statement body cannot be converted to an expression treeすると、次のコードをコンパイルしようとするとエラー「」が発生します。

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() { 
    Var1 = someLocalVar,
    Var2 = o.var2 };
}).ToArray();

エラーが何を意味するのか、そして何よりもそれを修正する方法がわかりません。何か助け?


6
このようなリストに変換してみてください。objects.List()。Select(...
nelson eldoro 2013年

回答:


114

あるobjectsLINQのツーSQLデータベースコンテキスト?この場合、=>演算子の右側にある単純な式のみを使用できます。その理由は、これらの式は実行されず、SQLに変換されてデータベースに対して実行されるためです。これを試して

Arr[] myArray = objects.Select(o => new Obj() { 
    Var1 = o.someVar,
    Var2 = o.var2 
}).ToArray();

102

IEnumerableコレクションのランバ式でステートメント本文を使用できます。これを試してください:

Obj[] myArray = objects.AsEnumerable().Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    };
}).ToArray();

注意:
この方法を使用する場合は、すべてのクエリ結果がメモリに格納されるため、コードの残りの部分に望ましくない副作用が生じる可能性があるため、この方法を使用するときは慎重に検討してください。


4
+1いいね!AsEnumerable()マスクを追加すると、問題がなくなります。
Joel、

5
これが本当の解決策であり、受け入れられた答えを適用することが難しい場合があります
Ferran Salguero 2013

15
いいえ、これは本当の答えではありません。クエリがクライアント側で実行されるようになります。:詳細については、この質問を参照してくださいstackoverflow.com/questions/33375998/...
ルークVoの

1
@DatVMそれはあなたが何をしようとしているのかに依存します。これは常に正しい選択であるとは限らず、もちろん常に間違った選択であるとは限りません。
Amir Oveisi、2015年

3
私はあなたに同意しますが、OPはEntityFrameworkを使用していると述べました。ほとんどの場合、EFで作業するときは、データベース側でできるだけ多くの作業を実行する必要があります。答えの中で大文字と小文字を区別してください。
Luke Vo

39

これは、ラムダ式を式ツリーに変換する必要がある場所(たとえば、linq2sqlを使用する場合)で、「ステートメント本文」を使用したラムダ式(つまり、中括弧を使用するラムダ式)を使用できないことを意味します。 。


37
あなた...少しエラーを言い換えました。@ティムロジャースの答えははるかに優れていました
vbullinger

2
@vbullingerあなたはある程度正しいですが、より一般的な意味では(linq-to-sqlのコンテキスト以外)、これはより直接的な答えです。AutoMapperエラー
mlhDev

1
vbullinger:でも、助けにはなりました。
Paul

7

あなたがしていること(Linq2Objects、Linq2Entities、Linq2Sql?)についてもっと知らなくても、これでうまくいくはずです:

Arr[] myArray = objects.AsEnumerable().Select(o => {
    var someLocalVar = o.someVar;

    return new Obj() { 
        Var1 = someLocalVar,
        Var2 = o.var2 
    }; 
}).ToArray();

11
これにより、クエリ可能オブジェクトが評価されます。
smartcaveman 2011

ただし、この状況では、とにかくすぐにToArray()を呼び出すので問題ありません。
smartcaveman 2011

2
必ずしもそうではありません-「o」の大きさを知っているのは誰ですか?私たちが望むすべてが2のときには、50点の性質を持つことができる
kdawg

1
この手法を使用する場合、呼び出す前に匿名型に使用するフィールドを選択します.AsEnumerable()
Blake Mitchell

4

このselectのオーバーロードを使用します。

Obj[] myArray = objects.Select(new Func<Obj,Obj>( o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
})).ToArray();

これは私にとっては機能しますが、Entity Frameworkと一緒に使用すると、このソリューションは、AsEnumerable()のように、dbcontextが最初にすべての行をメモリにロードするのを防ぎますか?
国会

2
@parliament:すべての行がメモリに読み込まれないようにするには、を使用する必要がありますExpression<Func<Obj,Obj>>
Mohsen 2014年

4

LINQ to SQLの戻りオブジェクトは、IQueryableインターフェイスを実装していました。だからSelectメソッド述語パラメーターの場合は、本体なしの単一ラムダ式のみを指定する必要があります。

これは、SQLコード用のLINQが、SQLサーバーなどのリモート側ではなくプログラム内で実行されないためです。この遅延読み込み実行タイプは、IQueryableを実装することで実現されました。その期待デリゲートは、以下のようなExpressionタイプクラスにラップされています。

Expression<Func<TParam,TResult>>

式ツリーは、ボディを含むラムダ式をサポートせず、次のような単一行のラムダ式のみをサポートします var id = cols.Select( col => col.id );

したがって、次のコードを試しても機能しません。

Expression<Func<int,int>> function = x => {
    return x * 2;
}

以下は期待どおりに動作します。

Expression<Func<int,int>> function = x => x * 2;

2

これは、TDelegateを含む型のラムダ式([parameters]) => { some code };を、Expression<TDelegate>ます。それがルールです。

クエリを簡略化します。あなたが提供したものは次のように書き直すことができ、コンパイルされます:

Arr[] myArray = objects.Select(o => new Obj()
                {
                   Var1 = o.someVar,
                   Var2 = o.var2
                } ).ToArray();

1

Arrの基本型Obj?Objクラスは存在しますか?コードは、ArrがObjの基本型である場合にのみ機能します。代わりにこれを試すことができます:

Obj[] myArray = objects.Select(o =>
{
    var someLocalVar = o.someVar;

    return new Obj() 
    { 
       Var1 = someLocalVar,
       Var2 = o.var2 
    };
}).ToArray();

1

あなたの特定のケースでは、本体は変数を作成するためのものであり、に切り替えるとIEnumerableすべての操作がクライアント側で処理されるように強制されます。次の解決策を提案します。

Obj[] myArray = objects
.Select(o => new
{
    SomeLocalVar = o.someVar, // You can even use any LINQ statement here
    Info = o,
}).Select(o => new Obj()
{
    Var1 = o.SomeLocalVar,
    Var2 = o.Info.var2,
    Var3 = o.SomeLocalVar.SubValue1,
    Var4 = o.SomeLocalVar.SubValue2,
}).ToArray();

編集:C#コーディング規約の名前を変更

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.