使用实体框架并使用orderby和skip / take的规范模式

时间:2014-08-11 13:06:52

标签: c# entity-framework specification-pattern

我已经选择了一个使用规范模式的项目,这是我之前没有使用的模式,我不得不去研究模式。我注意到它没有orderby和skip / take功能,而我无法在任何地方找到如何用模式实现这一点。

我正在努力思考如何将其添加到规范模式中。但是我遇到了问题,例如规范涉及" Expression>"而我不认为我可以将它与秩序等一起存储

基本上有一个这样的类:

public class Specification<T> : ISpecification<T>
{
    public Expression<Func<T, bool>> Predicate { get; protected set; }

    public Specification(Expression<Func<T, bool>> predicate)
    {
        Predicate = predicate;
    }

    public Specification<T> And(Specification<T> specification)
    {
        return new Specification<T>(this.Predicate.And(specification.Predicate));
    }

    public Specification<T> And(Expression<Func<T, bool>> predicate)
    {
        return new Specification<T>(this.Predicate.And(predicate));
    }

    public Specification<T> Or(Specification<T> specification)
    {
        return new Specification<T>(this.Predicate.Or(specification.Predicate));
    }

    public Specification<T> Or(Expression<Func<T, bool>> predicate)
    {
        return new Specification<T>(this.Predicate.Or(predicate));
    }

    public T SatisfyingItemFrom(IQueryable<T> query)
    {
        return query.Where(Predicate).SingleOrDefault();
    }

    public IQueryable<T> SatisfyingItemsFrom(IQueryable<T> query)
    {
        return query.Where(Predicate);
    }
}

这允许创建一个规范,传入一个where子句。它还允许使用&#34; And&#34;,&#34;或&#34;来链接规则。例如:

var spec = new Specification<Wave>(w => w.Id == "1").And(w => w.WaveStartSentOn > DateTime.Now);

如何为&#34; OrderBy&#34;添加方法?和&#34;采取&#34;?

由于这是现有代码,我无法做任何会影响现有代码的更改,因此重构它将是一项非常重要的工作。所以任何解决方案都需要很好地发挥作用。

1 个答案:

答案 0 :(得分:6)

怎么样

public class Specification<T> : ISpecification<T>
{
    public Expression<Func<T, bool>> Predicate { get; protected set; }
    public Func<IQueryable<T>, IOrderedQueryable<T>> Sort {get; protected set; }
    public Func<IQueryable<T>, IQueryable<T>> PostProcess {get; protected set;

    public Specification<T> OrderBy<TProperty>(Expression<Func<T, TProperty>> property)
    {
        var newSpecification = new Specification<T>(Predicate) { PostProcess = PostProcess } ;
        if(Sort != null) {
             newSpecification.Sort = items => Sort(items).ThenBy(property);
        } else {
             newSpecification.Sort = items => items.OrderBy(property);
        }
        return newSpecification;
    }

    public Specification<T> Take(int amount)
    {
        var newSpecification = new Specification<T>(Predicate) { Sort = Sort } ;
        if(PostProcess!= null) {
             newSpecification.PostProcess= items => PostProcess(items).Take(amount);
        } else {
             newSpecification.PostProcess= items => items.Take(amount);
        }
        return newSpecification;
    }

    public Specification<T> Skip(int amount)
    {
        var newSpecification = new Specification<T>(Predicate) { Sort = Sort } ;
        if(PostProcess!= null) {
             newSpecification.PostProcess= items => PostProcess(items).Skip(amount);
        } else {
             newSpecification.PostProcess= items => items.Skip(amount);
        }
        return newSpecification;
    }
}

TODO:

  • OrderByDescending的类似结构
  • 更新您的其他方法,以便在调用“And”时不会丢失“Sort”值和“PostProcess”值,例如
然后你满意的方法就变成了:

private IQueryable<T> Prepare(IQueryable<T> query) 
{
    var filtered = query.Where(Predicate);
    var sorted = Sort(filtered);
    var postProcessed = PostProcess(sorted);
    return postProcessed;
}

public T SatisfyingItemFrom(IQueryable<T> query)
{
    return Prepare(query).SingleOrDefault();
}

public IQueryable<T> SatisfyingItemsFrom(IQueryable<T> query)
{
    return Prepare(query);
}

TODO:检查Sort&amp; “准备”方法

中的PostProcess不为空

用法:

var spec = new Specification<Wave>(w => w.Id == "1")
              .And(w => w.WaveStartSentOn > DateTime.Now)
              .OrderBy(w => w.WaveStartSentOn)
              .Skip(20)
              .Take(5);