7

我经常需要通过字段来限制选择publishStartpublishEnd例如active

我在几个不同的表中有这些字段。所以应该只选择行,即

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

要定义扩展,您需要一个静态类。您可以将它放在您喜欢的任何名称空间中,只需记住将其包含在您的使用中。

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里面。这用于确保方法知道 、 和publishStartpublishEnd存在active。这应该是实现这些字段的类或定义它们的协定(接口)。

然后你会这样称呼它:

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

更多关于扩展方法的信息:http: //msdn.microsoft.com/en-us/library/bb383977.aspx


由于到处弹出很多评论,我将在此处添加对界面解决方案的简要说明...

不清楚三个过滤字段是否有通用实现或定义它们的接口。如果没有,为了上述工作,您也不会:

  1. 实现这些字段的基类。在这种情况下,您将替换YourEntityTypeYourBaseEntityType.
  2. 定义字段的接口。在这种情况下,您需要让您的类实现这些字段。如果类是自动生成的(例如,首先是实体框架模型/数据库),那么您可以实现部分类,让它们实现接口。在这种情况下,您将替换YourEntityTypeIYourContract.
于 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 回答