从一次删除需求,理解 DDD 中的 Repository 职责
起因:一次“看起来很简单”的删除需求
最近在实习中负责一个设备模板相关的模块,有一个接口需求很简单:
删除一个模板属性。
属性表里有个字段叫 draft,表示是否是草稿状态,只有草稿属性才能被删除。
听起来非常合理,对吧?
我的第一反应:那就 deleteById 吧?
一开始我写的代码大概是这样:
repository.deleteById(propertyId);
但很快我意识到不对——
如果属性不是草稿状态呢?
于是我改成了:
TemplateProperty property = repository.findById(propertyId)
.orElseThrow(() -> new IllegalArgumentException("属性不存在"));
if (!property.isDraft()) {
throw new IllegalStateException("只有草稿属性可以删除");
}
repository.deleteById(propertyId);
功能是没问题的,但我心里开始犯嘀咕:
🤔 JPA 的
deleteById本身不是就会检查 ID 是否存在吗?
那我前面这次findById会不会多此一举?
疑惑出现:那是不是 Repository 就该支持“按条件删除”?
顺着这个思路,我甚至开始想:
要不我直接写个
deleteByIdAndDraftTrue(id)?
这样不就一条 SQL 解决了吗?
但我越想越觉得哪里不对,却又说不上来。
我去问了 mentor
我把我的疑惑原封不动地问了 mentor,大概意思是:
Repository 不是应该“更智能一点”吗?
既然删除要判断条件,为什么不直接写进 Repository?
mentor 没有直接回答我,而是反问了我一句。
mentor 的反问,让我愣住了
他说:
“如果半年后,删除规则从
‘只能删草稿’
变成
‘草稿 + 创建人是自己 + 未被引用’,
你打算改哪一层代码?”
我当时愣了一下。
我才意识到:我把业务逻辑写错层了
如果我一开始写的是:
deleteByIdAndDraftTrue(id);
那后续规则变化就意味着:
- Repository 方法签名要改
- 所有调用点要改
- 甚至 SQL 也要改
而这些规则,本质上是:
“一个属性,当前是否允许被删除”
这不是持久化问题,而是领域规则。
Repository 到底该不该“聪明”?
mentor 给我的总结是:
Repository 要尽量“笨”一点。
它只负责数据存取,不负责业务决策。
于是正确的代码应该是:
TemplateProperty property = repository.findById(id)
.orElseThrow(...);
property.assertDeletable();
repository.delete(property);
而不是:
repository.deleteByIdAndDraftTrue(id);
我总结的一条判断标准
后来我给自己总结了一个非常好用的判断标准:
“这个条件如果未来会变,它就不该出现在 Repository。”
- 会变的 → 放领域 / 业务层
- 不会变的(如 tenantId、软删除)→ 可以放 Repository
回头再看那段代码
现在再回头看最初那段代码,我反而觉得:
- 多一次
findById并不是浪费 - 它是在明确表达业务语义
- JPA 的一级缓存也保证了不会产生额外 SQL
写在最后
这次看似很小的删除逻辑,其实让我第一次真正理解了:
为什么“分层”不是为了好看,
而是为了让变化发生时,
你知道该改哪一层。

浙公网安备 33010602011771号