Hibernate中如何正确管理两个子类继承自同一父类的实体
问题1:需求是否可以通过Hibernate继承机制实现?
你期望的三张独立表、子类表带父表外键的结构,和Hibernate的InheritanceType.JOINED继承策略的表结构非常接近,但存在一个核心冲突:JOINED策略默认子类表的主键就是关联父类表主键的外键,无法满足你要求的Client/RepairShop表拥有独立主键idclient/idrepairShop的需求。
同时你当前的继承实现存在两处明显错误:
- 父类
Auth已经定义了@Id主键,子类不需要重复定义@Id字段,不符合JPA规范 AuthRepository的泛型参数顺序写反,JpaRepository第一个参数为实体类型,第二个为主键类型,正确写法应为JpaRepository<Auth, Long>
问题2:当前实现是否合理,是否应该改用一对一关联?
当前实现不合理,更推荐放弃继承改用一对一单向/双向关联实现,原因如下:
- 你的业务场景本质是
Client/RepairShop拥有 鉴权信息,而非 是 鉴权信息的子类,用关联关系更符合领域模型的语义 - 可以完美匹配你期望的表结构,支持
Client/RepairShop拥有独立主键,同时通过idauth外键关联Auth表 - 不需要手动写触发器同步数据,配置级联操作即可实现新增
Client/RepairShop时自动插入Auth表数据 - Auth作为独立表的约束可以完全满足,支持单独对Auth表进行增删改查操作
问题3:更适配的数据库结构设计方案
你期望的三张表结构已经非常适配当前场景,不需要调整,仅需要调整实体映射逻辑即可:
实体代码参考
// Auth实体保持不变 @Entity public class Auth { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long authid; private String email; private String pass; private String role; // getter setter } // Client实体改为关联Auth @Entity public class Client { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long idClient; private String name; private String surname; // 配置一对一关联,idauth为外键,级联持久化会自动保存关联的Auth对象 @OneToOne(cascade = CascadeType.PERSIST, optional = false) @JoinColumn(name = "idauth", referencedColumnName = "authid") private Auth auth; @ManyToOne private RepairShop repairShop; // getter setter } // RepairShop实体同理 @Entity public class RepairShop { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long idRepairShop; private String nip; private String location; @OneToOne(cascade = CascadeType.PERSIST, optional = false) @JoinColumn(name = "idauth", referencedColumnName = "authid") private Auth auth; @OneToMany(cascade = CascadeType.ALL, mappedBy = "repairShop") private Set<Client> clients; // getter setter }
Repository修正
// 修正泛型顺序 public interface AuthRepository extends JpaRepository<Auth, Long>{ // 登录用查询方法 Optional<Auth> findByEmail(String email); } public interface ClientRepository extends JpaRepository<Client,Long> { Optional<Client> findByAuth_Authid(Long authid); } public interface RepairShopRepository extends JpaRepository<RepairShop, Long> { Optional<RepairShop> findByAuth_Authid(Long authid); }
前端对接适配建议
和Angular对接非常简单,按照以下逻辑实现即可:
- 登录接口接收前端传入的邮箱、密码,调用
AuthRepository的findByEmail方法查询Auth信息,校验密码后返回Auth的authid、role字段给前端 - 前端根据
role判断登录用户身份,调用对应的ClientRepository/RepairShopRepository的findByAuth_Authid方法获取用户的业务属性,也可以自定义登录接口直接拼接返回全量信息 - 新增
Client/RepairShop时,前端传入鉴权信息和业务属性,后端组装成Auth+业务实体的关联结构,调用Repository的save方法即可自动同步两张表的数据,不需要额外触发器
内容的提问来源于stack exchange,提问作者user14787328
相关产品推荐
相关产品推荐

