12

多くの方法で使用するフィルターがあります。

Expression<Func<Child, bool>> filter = child => child.Status == 1;

(実際はもっと複雑です)

そして、私は次のことをしなければなりません

return db.Parents.Where(parent => parent.Status == 1 &&
                                  parent.Child.Status == 1);

ここで、条件は上記のフィルターと同じです。

このメソッドでフィルターを再利用したい。しかし、方法がわかりません。私は試した

return db.Parents.Where(parent => parent.Status == 1 &&
                                  filter(parent.Child));

ただし、式はメソッドとして使用できません

4

6 に答える 6

4

式を組み合わせて linq-to-sql を使用できるようにしたい場合は、LinqKitをご覧になることをお勧めします。式の中を歩き回り、SQL 変換の前にすべての関数呼び出しをその内容に置き換えます。

このようにして、直接使用できるようになります

return db.Parents
       .AsExpandable()
       .Where(parent => parent.Status == 1 && filter(parent.Child));
于 2012-05-07T18:11:21.890 に答える
1

あなたはこれを試すことができます:

var compiledFilter = filter.Compile();
foreach (var parent in db.Parents.Where(parent => parent.Status == 1))
    if (compiledFilter(parent.Child))
        yield return parent;

すべての親をプルする必要がありますが、@ HugoRuneのソリューションとは異なり、Parent:Childの1:1の関係は必要ありません。

さまざまなタイプが関係しているため、これが状況に役立つとは思いませんが、念のため、 Expressionsを組み合わせる方法の例を次に示します。LINQ式を1つに組み合わせるにはどうすればよいですか。

編集:以前にを使用することを提案しましCompile()たが、それはLINQ-to-SQLでは機能しません。

于 2012-04-27T19:51:06.057 に答える
1

親と子の間に 1 対 1 の関係がある場合 (可能性は低いですが、例はそれを暗示しているようです)、次のようにできます。

  return db.Parents
  .Where(parent => parent.Status == 1)
  .Select(parent => parent.Child)
  .Where(filter)
  .Select(child=> child.Parent);

そうでなければ、それは難しいでしょう。

動的 linqでそれを行うこともできますが、それはおそらくやり過ぎです。

式ツリーを手動で生成することもできますが、これも非常に複雑です。私はそれを自分で試していません。

もちろん、最後の手段として、常に を呼び出すことができますyourQuery.AsEnumerable()。これにより、linq-to-sql がクエリをこの時点までの sql に変換し、クライアント側で残りの作業を実行します。次に、式を .compile() できます。ただし、linq-to-sql のパフォーマンス上の利点は失われます (また、compile() 自体は非常に低速です。実行されるたびに JIT コンパイラが呼び出されます)。

  return db.Parents
  .Where(parent => parent.Status == 1)
  .AsEnumerable()
  .Where(parent  => filter.Compile().Invoke(parent.Child))

個人的には、式を 2 回定義します。1 回は子用、もう 1 回は parent.child 用です。

   Expression<Func<Child, bool>> filterChild = child => child.Status == 1;
   Expression<Func<Parent, bool>> filterParent = parent => parent.Child.Status == 1;

最もエレガントではないかもしれませんが、おそらく他のソリューションよりも保守が容易です

于 2012-04-27T20:01:45.523 に答える
0

代わりに式を関数として使用できますか?

それ以外の:

Expression<Func<Child, bool>> filter = child => child.Status == 1;

同じ式をジェネリック関数として次のように使用します。

Func<Child, bool> filter = child => child.Status == 1;

次に、式を使用しようとしていたのとまったく同じ方法で関数を使用できるようになります。

return db.Parents.Where(parent => parent.Status == 1 &&
                                  filter(parent.Child));

編集:質問を誤解しました。これは悪い答えです。6年以上経ちましたが、これは機能しないというコメントがまだあります。衛生的な観点から、回答を削除するか、この編集を追加して、明らかに機能しないものの例として回答を立てる方がよいかどうかはわかりません. 私はそれについてアドバイスを受け付けています。

于 2012-05-09T14:30:47.223 に答える
0

これを思いつくだけで、これがうまくいくかどうかを確認してください

public interface IStatus { public int Status { get; set; } }
public class Child : IStatus { }
public class Parent : IStatus
{public Child Child { get; set; }  }

Func<IStatus, bool> filter = (x) => x.Status == 1;
var list = Parents.Where(parent => filter(parent) && filter(parent.Child));

お役に立てれば!

于 2012-04-27T20:29:24.350 に答える
0

外部ライブラリや式ツリーをいじる必要はありません。代わりに、ラムダ関数を記述してクエリ チェーンを使用し、LINQ の遅延実行を利用します。

それ以外の:

Expression<Func<Child, bool>> filter = child => child.Status == 1;

次のように書き換えます。

Func<IQueryable<Parent>, IQueryable<Parent>> applyFilterOnParent = query => query.Where(parent => parent.Child.Status == 1);

Func<IQueryable<Child>, IQueryable<Child>> applyFilterOnChild = query => query.Where(child => child.Status == 1);

今、代わりに:

return db.Parents.Where(parent => parent.Status == 1 && filter(parent.Child));

あなたは書ける:

var query = db.Parents.AsQueryable(); query = applyFilterOnParent(query); return query.Where(parent => parent.Status == 1);

また、他の LINQ クエリで applyFilter 関数を再利用できます。LINQ はラムダ関数を SQL に変換しないため、この手法は、ラムダ関数を LINQ-to-SQL と共に使用する場合に適しています。

于 2019-02-19T04:23:43.933 に答える