2013-01-08 40 views
7

は、私は頻繁に、私はいくつかの異なるテーブルでこれらのフィールドを持っているactiveLINQの拡張メソッド

publishEndpublishStartなどの分野でのSELECTを制限する必要があります。だから、だから、

a: active == true; 
b: publishStart < now; 
c: publishEnd > now; 

ある行だけ選択しなければならないが、例えば:

db.myTable.SingleOrDefault(a => (a.ID == _theID 
      //now the active and start-end part:    
         && ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
         && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
         && a.active == true)); 

これは少し長いですので、それを作成することが可能である場合、私は疑問に思う - 方法(拡張子は?)等:isActive()上記のスニペットの3株を提供

db.myTable.SingleOrDefault(a => (a.ID == _theID).isActive() 

どうすればいいですか? コードをクリーンアップするより良い方法はありますか?

+0

これらはすべて別々のテーブルにあります。コンテキストによって公開される単一のテーブルではありませんか?フィルタでは1つのコンテキストのみを使用している間は、プロパティが別のテーブルにあることをプリアンブルに示しているので、私は尋ねます。彼らがすべて同じテーブルにいる場合は、簡単です。異なるテーブルにある場合は、正しい答えが大きく変わります。 – casperOne

+0

その場合は、 'IsActive' ** before **' SingleOrDefault'を呼び出して、そのIDを持つ項目が1つしかない場合を除き、アクティブ項目を1つだけ取り除くことができます。 – Servy

答えて

13

拡張を定義するには、静的クラスが必要です。あなたはあなたが好きな名前空間にこれを置くことができます、あなたの使用にそれを含めることを忘れないでください。

public static class Extensions 
{ 
    public static IQueryable<T> Active<T>(this IQueryable<T> source) 
     where T : YourEntityType 
    { 
     return source.Where(a => ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
          && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
          && a.active == true); 
    } 
} 

通知YourEntityTypeがそこにあります。これは、メソッドがpublishStart,publishEnd、およびactiveの存在を認識していることを確認するために使用されます。これは、これらのフィールドを実装するクラスか、それを定義するコントラクト(インターフェイス)のいずれかでなければなりません。

あなたがそのようにようにこれを呼び出します。ここでは拡張メソッドの

var item = db.myTable.Active().SingleOrDefault(...); 

より:http://msdn.microsoft.com/en-us/library/bb383977.aspx


あらゆる場所にポップアップコメントがたくさんあるように、私は行きますよここにインターフェイスソリューションの簡単な説明を追加してください。

3つのフィルタリングされたfの共通の実装があるかどうかは不明ですそれらを定義するためのインタフェースを提供します。そうでない場合は、上記の作業を行うために、次のいずれかを行いません。

  1. これらのフィールドを実装する基本クラス。このシナリオではYourEntityTypeYourBaseEntityTypeに置き換えます。
  2. フィールドを定義するインタフェース。このシナリオでは、クラスにフィールドを実装させる必要があります。クラスが自動生成されている場合(たとえば、エンティティフレームワークモデル/ dbなど)、部分クラスを実装して、そのクラスを実装することができます。この場合、YourEntityTypeIYourContractに置き換えます。
+0

'IEnumerable 'の代わりに 'IQueryable 'を使う理由はありますか? – Default

+0

これは、OPが求めるものである 'SingleOrDefault'への呼び出しでは機能しません。 – casperOne

+1

@Default。私は過去に 'IEnumerable 'で多相性の問題を抱えていたので、 'IQueryable 'を使うことを好みます。 'IEnumerable 'と 'IQueryable 'の両方に拡張機能があるとすれば、 'IEnumerable 'を返すと、チェーン内で間違った拡張機能が呼び出され、遅延クエリではなく列挙される可能性があります。 –

3
public static class Extensions 
{ 
    public static IEnumerable<MyClass> isActive(this IEnumerable<MyClass> list) 
    { 
     return list.Where(a => 
       ((a.publishEnd > DateTime.Now) || (a.publishEnd == null)) 
       && ((a.publishStart <= DateTime.Now) || (a.publishStart == null)) 
       && a.active == true); 
    } 
} 
4

ちょうどこの

public interface IHaveAActivityPeriod 
{ 
    Boolean active { get; } 

    DateTime? publishStart { get; } 

    DateTime? publishEnd { get; } 
} 

ようなインターフェイスを定義し、関連するすべてのクラスに追加します。

public class Foo : IHaveAActivityPeriod { [...] } 

public class Bar : IHaveAActivityPeriod { [...] } 

今、あなたはIHaveAActivityPeriodを実装するすべてのインスタンスで

public static class Extensions 
{ 
    public static Boolean IsActive(this IHaveAActivityPeriod item) 
    { 
     var now = DateTime.Now; 

     return item.active && 
       (item.publishStart <= now) 
       (!item.publishEnd.HasValue || (item.publishEnd > now)); 
    } 
} 

この拡張メソッドを使用することができます。

var foo = new Foo(); 

var isFooActive = foo.IsActive(); 

var bar = new Bar(); 

var isBarActive = bar.IsActive(); 

一度に1つのエンティティを見るのではなく、シーケンスのフィルタリングを実行する拡張メソッドを構築する可能性は全くありませんでした。 flemの答えから拡張メソッドを取り出し、型制約としてインターフェイスにスローします。

public static class Extensions 
{ 
    public IQueryable<T> IsActive<T>(this IQueryable<T> sequence) 
     where T : IHaveAActivityPeriod 
    { 
     return source.Where(item => 
        item.active && 
        (item.publishStart <= now) && 
        (!item.publishEnd.HasValue || (item.publishEnd > now)); 

    } 
} 
+0

これはsqlに変換されないため、フィルタリングのための完全な評価が必要です。 –

+0

これは当てはまりますが、(カスタムプロバイダーなしで)SQLに変換可能な本当に良いソリューションはなく、LINQ to Objectsソリューションを提示することに決めました。 –