7

publishStartなどのフィールドで SELECT を頻繁に制限する必要がありますpublishEndactive

これらのフィールドは、いくつかの異なるテーブルにあります。したがって、行のみを選択する必要があります。

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));

これは少し長いので、次のような(拡張?)メソッドを作成できるかどうか疑問に思います。

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

ここisActive()で、上記のスニペットの 3 行を提供します。

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

4

3 に答える 3

13

拡張機能を定義するには、静的クラスが必要です。これは好きな名前空間に配置できますが、using に含めることを忘れないでください。

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 つのフィルター処理されたフィールドに共通の実装があるかどうか、またはそれらを定義するインターフェイスがあるかどうかは、質問では不明です。そうでない場合、上記が機能するためには、次のいずれかを行いません。

  1. これらのフィールドを実装する基本クラス。このシナリオでは、 に置き換えYourEntityTypeますYourBaseEntityType
  2. フィールドを定義するためのインターフェース。このシナリオでは、クラスにフィールドを実装させる必要があります。クラスが自動生成される場合 (たとえば、最初にエンティティ フレームワーク モデル/データベース)、部分クラスを実装して、それらにインターフェイスを実装させることができます。この場合、 に置き換えYourEntityTypeますIYourContract
于 2013-01-08T18:01:48.920 に答える
4

このようなインターフェースを定義するだけです

public interface IHaveAActivityPeriod 
{
    Boolean active { get; }

    DateTime? publishStart { get; }

    DateTime? publishEnd { get; }
} 

関連するすべてのクラスに追加します。

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

public class Bar : 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));
    }
}

を実装するすべてのインスタンスでIHaveAActivityPeriod

var foo = new Foo();

var isFooActive = foo.IsActive();

var bar = new Bar();

var isBarActive = bar.IsActive();

単一のエンティティを一度に見るのではなく、シーケンスのフィルタリングを実行する拡張メソッドを構築する可能性を完全に見逃していました。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));

    }
}
于 2013-01-08T18:02:13.333 に答える
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);
    }
}
于 2013-01-08T18:00:40.307 に答える