2016-05-27 3 views
1

大きなコードチャンクがありますが、実際のコードはそれほど重要ではありませんが、私がしようとしていることを示すために含まれています。LINQ用式の結合

私は公共の静的な式> G​​etFreeSpotCount(...)

にこの方法を持っているが、別の方法では、私は再利用したい式を返します

式自体は数を示す数値を返します特定の基準を満たす[モデル]のリストの[モデル]。私はそんなにコード

を複製することを避けるためにしたい

私は[モデル] 'sを超える数が0以下

よりも大きい場合、新しいメソッドがすべてを返すようにしたいが、私が現在持っているもののコードです

:私のようなものをやってみたかった

public static Expression<Func<ExamTimeSlot, bool>> GetExamTimeSlotsWithFreeSpotsFor(List<Guid> drivingSchoolIds) 
{ 
    return ets => 
    (ets.Participants 
     - ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Count(e => !ets.ExamTimeSlotReservations.Any(r => r.DrivingSchoolId == e.BookedByDrivingSchoolId)) 
     - ((int?)ets.ExamTimeSlotReservations.Sum(r => (ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Where(e => e.BookedByDrivingSchoolId == r.DrivingSchoolId).Count() 
      - r.ReservedSpots) > 0 ? (ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Where(e => e.BookedByDrivingSchoolId == r.DrivingSchoolId).Count() - r.ReservedSpots) : 0) ?? 0) 
     - ((int?)ets.ExamTimeSlotReservations.Sum(r => r.ReservedSpots) ?? 0) 
     + ((((int?)ets.ExamTimeSlotReservations.Where(r => drivingSchoolIds.Any(id => r.DrivingSchoolId == id)).Sum(r => r.ReservedSpots) ?? 0) 
      - ets.Exams.Where(ex => drivingSchoolIds.Any(id => ex.BookedByDrivingSchoolId == id) && ex.Status == ExamStatus.Pending).Count()) >= 0 ? 
       (((int?)ets.ExamTimeSlotReservations.Where(r => drivingSchoolIds.Any(id => r.DrivingSchoolId == id)).Sum(r => r.ReservedSpots) ?? 0) 
       - ets.Exams.Where(ex => drivingSchoolIds.Any(id => ex.BookedByDrivingSchoolId == id) && ex.Status == ExamStatus.Pending).Count()) 
       : 0)) > 0; 
} 

public static Expression<Func<ExamTimeSlot, int>> GetFreeSpotCountFor(List<Guid> drivingSchoolIds) 
{ 
    return ets => 
    ets.Participants 
     - ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Count(e => !ets.ExamTimeSlotReservations.Any(r => r.DrivingSchoolId == e.BookedByDrivingSchoolId)) 
     - ((int?)ets.ExamTimeSlotReservations.Sum(r => (ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Where(e => e.BookedByDrivingSchoolId == r.DrivingSchoolId).Count() 
      - r.ReservedSpots) > 0 ? (ets.Exams.Where(ex => ex.Status == ExamStatus.Pending).Where(e => e.BookedByDrivingSchoolId == r.DrivingSchoolId).Count() - r.ReservedSpots) : 0) ?? 0) 
     - ((int?)ets.ExamTimeSlotReservations.Sum(r => r.ReservedSpots) ?? 0) 
     + ((((int?)ets.ExamTimeSlotReservations.Where(r => drivingSchoolIds.Any(id => r.DrivingSchoolId == id)).Sum(r => r.ReservedSpots) ?? 0) 
      - ets.Exams.Where(ex => drivingSchoolIds.Any(id => ex.BookedByDrivingSchoolId == id) && ex.Status == ExamStatus.Pending).Count()) >= 0 ? 
       (((int?)ets.ExamTimeSlotReservations.Where(r => drivingSchoolIds.Any(id => r.DrivingSchoolId == id)).Sum(r => r.ReservedSpots) ?? 0) 
       - ets.Exams.Where(ex => drivingSchoolIds.Any(id => ex.BookedByDrivingSchoolId == id) && ex.Status == ExamStatus.Pending).Count()) 
       : 0); 
} 

私はExpression.GreaterThanを最初の式で使用しようとしましたが、結果とモデルが必要なので、[モデル]は動作させる方法を見つけられませんでした。

+0

あなたは、コードをエスケープするために 'を使用することになっていない(つまり、例えば、テキストの塊で、単一のクラス名のためです)の代わりに適切なコードの整形を使う(4つのスペースで各行をidentを)私たちは今から定型化して適切なコードビューを得るようにします(あなたのためにそれを編集するつもりですが、次回はそれを念頭に置いてください) –

+0

ああ、最後の13秒で誰か他の人がそれを修正しましたよ –

+0

ありがとう、インデントについての部分を逃した、将来それを使用することを確認します。 – Peterbom

答えて

1

これを行うには、実際には(サードパーティのライブラリを使用しないと)簡単な方法はありません。 のように、はあなたが書いたことを簡単に行うことができますが、私たちは表現木を作成するときに依存している構文上の砂糖のために誤解を招いています。

public static Expression<Func<ExamTimeSlot, bool>> GetExamTimeSlotsWithFreeSpotsFor(List<Guid> drivingSchoolIds) 
{ 
    var param = Expression.Parameter(typeof(ExamTimeSlot)); 

    //We want to create a new lambda which will invoke `GetFreeSpotCountFor` with our parameter, and then check it's greater than 0 
    var newBody = 
     Expression.GreaterThan(
      //View this as GetFreeSpotCountFor(drivingSchoolIds)(param) - where param will be given to us when this lambda is invoked 
      Expression.Invoke(
       GetFreeSpotCountFor(drivingSchoolIds), 
       param 
      ), 
      //Pass the right-hand value (0) to the GreaterThan check 
      Expression.Constant(0) 
     ); 

    var lambda = Expression.Lambda<Func<ExamTimeSlot, bool>>(newBody, param); 
    return lambda; 
} 

我々はExpressionオブジェクトを持ってたら、我々は手動式ツリーを構築する必要があります。

以上が起動し、代替は、既存のラムダの.Bodyを確認し、それに.GreaterThanを追加して、全く新しいラムダを返すことです0に結果を比較し、新しいラムダ、ラムダであなたをラップします。

すなわち:

public static Expression<Func<ExamTimeSlot, bool>> GetExamTimeSlotsWithFreeSpotsFor(List<Guid> drivingSchoolIds) 
{ 
    //This grabs the existing lambda, which we will work on 
    var oldLambda = GetFreeSpotCountFor(drivingSchoolIds); 
    var newBody = 
     //Invoke `GreaterThan` directly on the old lambda's Body 
     Expression.GreaterThan(
      oldLambda.Body, 
      //Pass the right-hand value (0) to the GreaterThan check 
      Expression.Constant(0) 
     ); 

    //Now, we need to pass in the old parameters, and build a new lambda. 
    var lambda = Expression.Lambda<Func<ExamTimeSlot, bool>>(newBody, oldLambda.Parameters); 
    return lambda; 
} 
+0

驚くべきことに、これは私が望んでいたのとまったく同じ問題を解決しました。試してみると、実際には解決策のようなものが出てきましたが、「oldLambda.Paramenters」は私が欠けていたものでした。 おかげで再び! :) – Peterbom

+0

@Peterbomいいえ、心配の仲間:) – Rob

0

具体的には、クエリ呼び出しを組み合わせるのではなく、式を組み合わせたいのですか?これを行う簡単な方法の1つは、GetExamTimeSlotsWithFreeSpotsForが式を取得して返すのではなく、クエリーを受け取り、そのクエリーに2つのwhere句を追加することです(それぞれが格納した式です)。

public static IQueryable<ExamTimeSlot> WhereExamTimeSlotsWithFreeSpotsFor (IQueryable<ExamTimeSlot> Source, List<Guid> drivingSchoolIds) 
    { 
     var FirstFilter = GetFreeSpotCountFor(drivingSchoolIds); 
     var SecondFilter = GetExamTimeSlotsWithFreeSpotsFor(drivingSchoolIds); 
     return Source 
       .Where(FirstFilter) 
       .Where(SecondFilter);     
    } 

何も組み合わせる必要がないように、LINQプロバイダに2つのwhere句を1つに結合させます。

実際に手動で式を結合したい場合は、サードパーティ製のAPIを使用するか、式ツリーを直接操作する必要があります(コンパイラの魔法を楽しむだけでなく) 。 2つの式をとり、その間に演算子を入れても同じ結果が得られない場合は難しくありません。

+0

コメントをいただきありがとうございます。私が当初考えていたものに最も近いので、私は上記の解決策を選んだが、これはうまくいったかもしれない。 – Peterbom

+0

@Peterbomちょうどいいプロバイダがコンパイルされることを覚えておいてください。(A).Where(B)と同じSQLに.Where(A&B)は味の問題ですが、他の人には、APIの側に慣れている人はほとんどいません。何も問題はありませんが、私が個人的に選ぶ解決策ではありません。 –

関連する問題