Ardalis.Specification库如何组合多个Specification实现可组合查询
Ardalis.Specification 多规则组合实现方案
Ardalis.Specification 原生支持多个Specification的组合拼接,完全可以满足复杂动态查询场景下拆分规则、避免大量条件判断的需求,和整洁架构的仓储模式适配度很高。
核心组合方法
你不需要修改已有的三个独立Specification代码,直接通过Query.AddSpecification()方法就能把多个规则叠加,所有通过该方法添加的Where条件默认会以AND逻辑拼接,正好匹配你需要的「同时满足资料完成、指定国家、创建时间晚于指定日期」的查询需求。
对应组合后的Specification实现如下:
public class ContactTargetQuerySpec : Specification<Contact> { public ContactTargetQuerySpec(string countryCode, DateTime compareDate, bool isComplete = true) { Query // 叠加完成状态筛选规则 .AddSpecification(new ContactByCompletion(isComplete)) // 叠加创建时间筛选规则 .AddSpecification(new ContactByCreationDateSuperiorThan(compareDate)) // 叠加国家归属筛选规则 .AddSpecification(new ContactByCountry(countryCode)); } }
这个组合后的Specification和普通单规则Specification用法完全一致,直接传入仓储的查询方法即可执行。
适配你的业务场景的实践方式
- 动态增减筛选条件:你可以把每个筛选维度都拆成独立的细粒度Specification,在构造组合Specification时根据入参判断是否追加对应规则,完全替代零散写在Where里的条件判断。示例代码如下:
public class ContactDynamicFilterSpec : Specification<Contact> { public ContactDynamicFilterSpec(ContactQueryRequest request) { // 仅当传入完成状态参数时追加对应筛选 if (request.IsComplete.HasValue) { Query.AddSpecification(new ContactByCompletion(request.IsComplete.Value)); } // 仅当传入起始时间参数时追加时间范围筛选 if (request.CreateTimeStart.HasValue) { Query.AddSpecification(new ContactByCreationDateSuperiorThan(request.CreateTimeStart.Value)); } // 仅当传入国家编码时追加归属地筛选 if (!string.IsNullOrEmpty(request.CountryCode)) { Query.AddSpecification(new ContactByCountry(request.CountryCode)); } } }
- 按需加载关联实体:把关联实体加载(Include/ThenInclude)逻辑也拆成独立的Specification,比如写专门的
ContactWithOrdersSpec、ContactWithTagsSpec,需要加载对应关联数据时就追加对应Specification即可。关联实体内部的筛选条件,可以直接写在对应Include的子查询里,组合时会自动合并生效。 - 时间范围大小比较:你示例里的DateTime大于/小于筛选逻辑写在独立Specification里即可,组合时不会有任何冲突,支持任意数值、时间类型的比较规则拼接。
注意事项
- 排序逻辑会被后添加的Specification覆盖:如果多个子Specification都配置了OrderBy/OrderByDescending规则,最终生效的是最后一个添加的排序。建议把排序逻辑和筛选逻辑拆分,做成独立的排序类Specification,按需追加,避免规则耦合。
- 分页、忽略全局过滤器这类影响整个查询的配置,不要写在细粒度的子Specification里,统一放在最外层的组合Specification中配置,避免规则互相覆盖。
- 如果需要实现OR逻辑的组合(即满足A规则或满足B规则),不要直接用AddSpecification,用库内置的
OrSpecification<T>包装两个待组合的规则再添加即可,示例:Query.AddSpecification(new OrSpecification<Contact>(specA, specB))。
内容的提问来源于stack exchange,提问作者Arkena
相关产品推荐
相关产品推荐

