删除边界

Odoo 删除为什么总容易出事故:unlink、ondelete、业务保护边界到底怎么想

删除逻辑看起来简单,实际上很容易把数据一致性、业务保护、关系约束一起打穿。本文讲清 unlink 和 ondelete 背后的设计边界。

Odoo 开发
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

在 Odoo 里,“删除一条记录”从来都不只是数据库层面的一个小动作。

它同时可能影响:

  • 业务流程完整性
  • 关系对象一致性
  • 审计留痕
  • 用户是否还能追溯历史

所以 unlink()ondelete 真正讨论的不是“怎么删”,而是:

什么可以删、删了以后谁跟着变、哪些场景根本不应该物理删除。


为什么删除问题总是高风险

因为创建和修改通常是在“增加信息”, 而删除是在“直接拿走一段事实”。

一旦删错,常见后果是:

  • 业务链断掉
  • 下游引用失效
  • 报表不一致
  • 用户以为系统丢数据

这也是为什么成熟系统往往对删除特别保守。

Odoo 也一样。


unlink() 最直接的作用当然是删除记录。

但从业务层看,它更像:

正式请求把这条业务对象从系统里移除。

这意味着它通常不该只是“我能删就删”。

很多模型在 unlink() 里都会加入业务保护,比如:

  • 已确认单据不允许删
  • 已过账凭证不允许删
  • 已完成流程不允许删
  • 有下游引用时不允许删

所以 unlink() 往往也是业务边界的一部分。


ondelete 在解决什么问题

ondelete 更偏向关系层。

它关心的是:

  • 当被引用对象删除时
  • 这条关系应该怎么办

常见语义你可以先理解成:

  • restrict:不让你删
  • cascade:跟着删
  • set null:关系断开,引用置空

所以 ondelete 不是在问“删不删当前对象”,而是在问:

如果上游对象消失了,下游关系该如何收尾。


为什么 cascade 很方便但也危险

因为它省事。

上游一删,下游跟着清掉,看起来很干脆。

但危险在于:

  • 你可能低估了波及范围
  • 一次删除会级联带走很多数据
  • 用户可能根本不知道后面还有哪些依赖对象

所以 cascade 适合那些真正属于“强从属、无独立业务意义”的子对象。

如果子对象本身已经承载业务事实,就要非常慎重。


为什么很多业务对象不该物理删除

因为很多记录一旦进入正式业务阶段,它的价值已经不只是“当前还用不用”。

它还可能是:

  • 历史依据
  • 审计线索
  • 报表来源
  • 责任追踪依据

这时更稳的做法往往不是删,而是:

  • 归档
  • 取消
  • 作废
  • 关闭状态

也就是说:

很多业务对象真正需要的是“退出使用”,不是“从世界上抹掉”。


实战里最容易踩的 5 个坑

1. 把删除当成普通清理动作

结果误删业务历史。

2. cascade 用得太随意

一个删除带崩整条链。

3. 本该归档的对象硬删

后面报表和追溯都出问题。

4. 只看数据库约束,不看业务边界

技术能删,不代表业务该删。

这类 bug 很隐蔽,也很伤。


一个特别实用的判断方法

设计删除策略时,先问这几个问题:

1. 这条记录是不是正式业务事实?

如果是,优先考虑不物理删除。

2. 下游对象有没有独立业务意义?

如果有,别轻易 cascade。

3. 用户真正想要的是“消失”,还是“停用/作废”?

很多需求其实不是删。

4. 删掉之后,审计、报表、追溯还能不能站得住?

这一步非常关键。


一句话记忆法

把这套机制记成一句话:

unlink() 决定当前对象能不能被删,ondelete 决定关联对象在上游删除后怎么收尾,而成熟业务对象很多时候更该归档或作废,而不是物理删除。

理解这一句,Odoo 删除策略会稳很多。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。