2. 配方数据模型设计:实体定义、字段权限标记与数据归属
数据模型这东西,说白了就是给配方“画个像”。你想想看,一个配方在系统里到底长什么样?哪些字段能改、哪些不能改?它属于谁?这些问题不搞清楚,后面的权限控制根本无从下手。我个人习惯,在设计阶段就把这些边界划清楚,省得后期返工。
2.1 配方实体定义:核心字段与结构
我们先从最基础的实体定义开始。一个典型的配方实体,我通常会把它拆成三个层次:配方头、配方项和工艺参数。为什么这么分?因为不同层级的字段,权限敏感度完全不同。
| 层级 | 实体名称 | 核心字段示例 | 权限敏感度 |
|---|---|---|---|
| L1 | 配方头 (RecipeHeader) | 配方ID、名称、版本、状态、创建人、所属产线 | 高(元数据) |
| L2 | 配方项 (RecipeItem) | 物料编码、用量、单位、替代料清单 | 中(BOM数据) |
| L3 | 工艺参数 (ProcessParam) | 温度设定、压力值、时间窗口、公差范围 | 极高(核心工艺) |
关键点:配方头中的“状态”字段(如:草稿、已审核、已发布、已锁定)是权限控制的开关。我在项目中遇到过,有人直接修改了已发布配方的状态,导致产线用了错误版本。所以,状态变更必须走审批流。
下面是一个简化后的配方实体定义代码示例,我用的是 Java 风格,但思路通用:
public class RecipeHeader {
private String recipeId; // 配方唯一标识
private String recipeName; // 配方名称
private int version; // 版本号
private String status; // 状态:DRAFT, REVIEWED, RELEASED, LOCKED
private String ownerId; // 所有者ID
private String lineId; // 所属产线ID
private List<RecipeItem> items; // 配方项列表
private List<ProcessParam> params; // 工艺参数列表
// getters/setters 省略
}
2.2 字段权限标记:谁可以改什么?
实体定义好了,接下来就是给每个字段打上“权限标签”。我习惯用位掩码或者枚举组合来做这件事。你想想看,一个字段可能有多种操作:可读、可写、可审批、可删除。用位掩码可以很优雅地组合这些权限。
举个例子,对于工艺参数中的“温度设定”字段:
- 操作员:只能读,不能写(位掩码:0x01)
- 工艺工程师:可读可写,但不能删除(位掩码:0x03)
- 管理员:全部权限(位掩码:0x0F)
我的小技巧:在数据库里,我会额外加一个字段叫 permMask,用整数存储。比如 permMask = 3 表示可读+可写。这样查询时直接用位运算,性能很好。我曾经在一个高并发项目里用这种方式,权限判断耗时从毫秒级降到了微秒级。
下面是一个字段权限标记的配置示例:
@Entity
public class FieldPermission {
private String fieldName; // 字段名,如 "temperatureSet"
private int readMask; // 可读的角色位掩码
private int writeMask; // 可写的角色位掩码
private int approveMask; // 可审批的角色位掩码
// 判断当前角色是否有写权限
public boolean canWrite(int roleMask) {
return (roleMask & writeMask) != 0;
}
}
2.3 数据归属关系:配方到底属于谁?
这个问题看似简单,其实坑很多。配方不是孤立存在的,它和多个实体有归属关系。我一般会画一张归属关系图来理清脉络。
核心的归属关系包括:
- 用户 → 配方:配方有创建者和所有者。所有者可以转让。
- 角色 → 配方:某些配方只能由特定角色(如高级工程师)修改。
- 组织 → 配方:配方属于某个部门或工厂,跨组织访问需要授权。
- 产线 → 配方:配方绑定到具体产线,换线时配方自动切换。
避坑指南:我曾经犯过一个错误——只考虑了用户到配方的直接归属,忽略了组织归属。结果一个工厂的配方被另一个工厂的人误改了,因为两个工厂共用了同一个配方ID池。后来我加上了 orgId 作为分区键,才彻底解决。
下面我用一张 SVG 图来展示完整的配方数据归属关系:
2.4 实战中的设计决策
最后,我想分享几个我在实际项目中踩过的坑,以及对应的设计决策:
- 字段权限粒度:别一开始就搞到字段级,太细了维护成本高。我建议先做到实体级,等业务稳定了再细化到字段级。
- 归属关系缓存:每次修改都查数据库确认归属?太慢了。我会在 Redis 里缓存一份
recipeId → {ownerId, orgId, lineId}的映射,过期时间设 5 分钟。 - 版本与归属联动:配方升级时,归属关系要不要变?我的经验是:版本升级不改变归属,除非显式转让。
总结一下:配方数据模型设计,核心就是三件事——实体定义(配方长什么样)、字段权限标记(谁可以改什么)、数据归属关系(配方属于谁)。这三件事搞定了,后面的权限控制逻辑就是水到渠成的事。