news 2026/9/19 16:26:43

eShopOnWeb商品查询拆解:Specification模式动态过滤与分页完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
eShopOnWeb商品查询拆解:Specification模式动态过滤与分页完整指南

eShopOnWeb商品查询拆解:Specification模式动态过滤与分页完整指南

【免费下载链接】eShopOnWebSample ASP.NET Core 8.0 reference application, now community supported: https://github.com/NimblePros/eShopOnWeb项目地址: https://gitcode.com/gh_mirrors/es/eShopOnWeb

🛒 eShopOnWeb 是一个基于 ASP.NET Core 8.0 的开源电商参考应用,它的商品查询功能完整演示了Specification(规约)模式如何实现动态过滤与分页。本文带你从请求入口一路追踪到数据库条件拼接,看它是如何用不到 20 行代码写出"品牌+类型+页码"组合查询的——全程几乎不用写 SQL 拼接代码。

为什么需要 Specification 模式?

在传统写法里,"按品牌筛选 + 按类型筛选 + 分页"往往要写一个带一堆if判断的查询方法,参数组合一多,代码就成了面条:

  • 每加一个筛选条件,就要改方法签名和内部逻辑
  • 查询条件散落在各处,难以复用、难以单独测试

Specification 模式的思路是:把"查什么"封装成一个个可复用的对象。每个筛选规则是一个独立的小类,查询执行器负责把它翻译成 SQL。规则之间互不影响,随便组合。

eShopOnWeb 使用的是社区流行的Ardalis.Specification库,所有规约类集中在 Specifications 目录下。

查询全链路:从 URL 参数到 SQL

一次商品列表请求的流转路径非常清晰:

  1. 用户在首页选择品牌、类型并翻页,浏览器带上pageIdBrandFilterApplied等查询参数
  2. 页面模型 Index.cshtml.cs 的OnGet接收参数,转交给服务层
  3. 服务层 CatalogViewModelService.cs 构建 Specification 对象,调用仓储执行查询
  4. 仓储将 Specification 翻译成数据库查询条件并返回结果

拆解 4 个核心 Specification 类

商品相关的规约共有 4 个,都是"小而美":

1️⃣ 动态过滤:CatalogFilterSpecification

CatalogFilterSpecification.cs 是整个过滤的核心,全部逻辑就一行Where

Query.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) && (!typeId.HasValue || i.CatalogTypeId == typeId));

技巧在于!brandId.HasValue ||这个短路判断:参数没传时该条件自动失效,传了才生效。两个参数任意组合(都传、只传一个、都不传),一个类全部覆盖,这就是"动态过滤"的精髓。

2️⃣ 过滤 + 分页:CatalogFilterPaginatedSpecification

CatalogFilterPaginatedSpecification.cs 在相同过滤条件上追加了.Skip(skip).Take(take),负责只取当前页数据。它还处理了一个细节:当take为 0 时自动改为int.MaxValue,相当于"返回全部",避免分页参数异常时查不到数据。

3️⃣ 按 ID 批量查:CatalogItemsSpecification

CatalogItemsSpecification.cs 接收一组 ID,用于购物车结算等场景按 ID 批量取出商品,params int[] ids让调用侧可以传入任意数量。

4️⃣ 按名称查:CatalogItemNameSpecification

CatalogItemNameSpecification.cs 按商品名精确查找,管理端编辑商品时用来防止重名。

分页是怎么算出来的?

真正的分页"数学"发生在服务层 CatalogViewModelService.cs 的GetCatalogItems方法里:

  • 取当前页数据new CatalogFilterPaginatedSpecification(itemsPage * pageIndex, itemsPage, brandId, typeId)—— 页码 × 每页条数就是Skip的偏移量,每页条数取自 Constants.cs 中的ITEMS_PER_PAGE = 10
  • 取总数:单独用一个纯过滤的CatalogFilterSpecification执行CountAsync,只数数量不取实体,性能友好
  • 算总页数:总数 ÷ 每页条数向上取整,连同当前页码一起装进 PaginationInfoViewModel.cs

注意这里"取数据"和"数总数"用了两个不同的 Specification——一个带分页、一个不带,各取所需。这正是规约对象可以随意裁剪、组合的威力。

前端分页条:条件自动跟随

分页链接由 _pagination.cshtml 渲染,它的巧妙之处在于:把当前请求的全部查询参数原样复制到新链接上,只替换pageId。也就是说,你正在按"品牌 A + 类型 B"筛选,翻页后筛选条件依然保留,用户不会莫名其妙看到全部商品。

总结:这套设计值得抄作业的地方

规则即对象:每个筛选条件是独立类,加新规则零侵入 ✅参数可空即可选!xxx.HasValue ||让动态条件一行搞定 ✅取数与计数分离:分页查询和总数查询各司其职 ✅分层清晰:页面模型只管传参,服务层构建规约,仓储只管执行

所有规格源码都在 src/ApplicationCore/Specifications/,单元测试覆盖了大部分规约,见 tests/UnitTests/ApplicationCore/Specifications/。想在自己项目里落地同样的动态过滤与分页,照这个"一个条件一个类"的结构抄即可。

【免费下载链接】eShopOnWebSample ASP.NET Core 8.0 reference application, now community supported: https://github.com/NimblePros/eShopOnWeb项目地址: https://gitcode.com/gh_mirrors/es/eShopOnWeb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 16:26:23

STM32H750VBT6 Keil5烧录失败排查:Flash算法与选项字节配置指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 16:25:55

UL耐压测试原理与实操:绝缘验证不是简单加压

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 16:24:39

高中排列组合底层逻辑:加法原理与乘法原理的适用边界

简介:本资源是一份面向高中数学学习者与教师的排列组合系统性复习资料,聚焦高考核心考点与典型题型突破。内容全面覆盖加法原理、乘法原理、排列与组合定义及公式推导、组合数性质、九大解题策略(如捆绑法、插空法、定序除法、小团体处理、隔…

作者头像 李华
网站建设 2026/9/19 16:24:10

Mac环境变量可视化诊断:解决JDK/PATH配置失效

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 16:23:18

ENSP与VirtualBox兼容性全解析:从报错40到稳定运行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华