规范模式与实体框架和使用顺序和跳过/取

本文关键字:顺序 框架 范模式 模式 实体 | 更新日期: 2023-09-27 18:17:40

我选择了一个使用规范模式的项目,这是一个我以前没有使用过的模式,我必须去研究这个模式。我注意到它没有OrderBySkip/Take功能,而且我找不到任何地方显示如何用模式实现这一点。

我正在努力思考如何最好地将其添加到规范模式中。但是我遇到了一些问题,比如规范处理"Expression<Func<T, bool>>",而我认为我不能将其与order的etc一起存储

基本上有这样一个类:

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子句。它还允许用"与"、"或"链接规则。例如:

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

如何为"OrderBy"answers"Take"添加方法?

由于这是现有的代码,我不能做任何会影响现有代码的更改,重构它将是一项相当繁重的工作。因此,任何解决方案都需要很好地利用现有的内容。

规范模式与实体框架和使用顺序和跳过/取

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

待办事项:

  • 类似orderbydescent
  • 的构造
  • 更新你的其他方法,所以"Sort"值和"PostProcess"值不会在你调用"and"时丢失,例如

让你满意的方法变成:

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 &在"Prepare"方法中PostProcess不为空

用法:

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