Doctrine2 SINGLE_TABLE继承鉴别器更新及merge方法替代方案咨询
问题1:通过继承区分客户不同状态的做法是否合理
这个思路的出发点没有问题,拆分限界上下文、避免核心实体变成上帝类是合理的架构设计方向,但用Doctrine单表继承映射可变的实体状态属于踩了框架的设计雷区。
Doctrine的单表继承设计的前提是「实体类型自创建后固定不变」,比如你创建的是Customer实例,那这条记录对应的类型永远是Customer,不允许变更为其他子类,所以鉴别器字段默认不支持通过ORM层面更新,你现在手写原生SQL修改的方式本来就不符合该特性的设计预期。
更稳妥的实现方案有两种:
- 优先推荐用状态模式替换继承实现:给
AbstractCustomer加status字段标记客户状态,不同状态的差异化逻辑封装到对应状态类中,既避免上帝类,也完全避开了鉴别器字段变更的问题 - 如果一定要保留单表继承的结构,可以删除原有
Customer记录后再插入同ID的DeletedCustomer,虽然多了一次删写操作,但完全符合ORM规范,不需要手写原生SQL
问题2:如何替代EntityManager->merge()的使用
merge()的核心作用是将游离态的实体合并到当前的UnitOfWork中,你这个从JWT获取客户实例的场景有非常成熟的替代方案:
- 先通过JWT中拿到的客户ID,用Repository从当前EntityManager中查询受管理的实体实例:
$managedCustomer = $customerRepository->find($customer->id()); - 如果是用状态模式的实现,直接给
$managedCustomer调用状态变更方法,之后正常flush即可,完全不需要做实体替换 - 如果保留单表继承的结构,就把查询到的
$managedCustomer调用EntityManager->remove()删除,再正常persist新创建的DeletedCustomer实例后flush,全程不需要用到merge()方法
你现在直接new同ID的DeletedCustomer再调用merge的逻辑,本质就是想覆盖同ID的旧记录,直接先查旧实例处理完全符合Doctrine的正常工作流,也完美兼容Doctrine3对merge()的废弃规则。
内容的提问来源于stack exchange,提问作者Clark
相关产品推荐
相关产品推荐

