JPA/Hibernate使用@SecondaryTable如何实现INNER JOIN返回两表共有的记录
问题原因
你当前使用的@SecondaryTable注解默认的关联策略是左外连接,从表allergens的记录默认是可选存在的,所以就算没有对应主键的关联记录,主表meal的数据也会正常返回,关联的从表字段如果是包装类型则会赋值为null。
解决方案
方案1:修改@SecondaryTable配置(适配现有实体结构,改动最小)
只需要给@SecondaryTable注解添加optional = false属性即可,该属性标识从表记录必须存在,Hibernate会自动将关联逻辑改为内连接,仅返回两张表主键同时匹配的记录。
修改后的代码如下:
@Entity @Table(name = "meal") // 新增optional = false属性 @SecondaryTable(name = "allergens", pkJoinColumns = @PrimaryKeyJoinColumn(name = "meal_id"), optional = false) class Meal { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") Long id; @Column(name = "name") String name; @Column(name = "description") String description; @Column(name = "price") BigDecimal price; @Column(name = "peanuts", table = "allergens") boolean peanuts; @Column(name = "celery", table = "allergens") boolean celery; @Column(name = "sesame_seeds", table = "allergens") boolean sesameSeeds; // 标准getter、setter方法 }
该方案还会自动增加数据校验:新增/修改Meal实体时,过敏相关字段必须赋值,否则会抛出持久化异常,符合“餐品必须对应过敏信息”的业务约束。
方案2:拆分关联实体(适合后续需要单独维护过敏表的场景)
如果后续你有单独操作allergens表的需求,可以拆分出独立的Allergens实体,通过共享主键+optional=false的@OneToOne关联实现内连接,代码示例如下:
@Entity @Table(name = "allergens") class Allergens { @Id Long mealId; boolean peanuts; boolean celery; boolean sesameSeeds; // 标准getter、setter方法 } @Entity @Table(name = "meal") class Meal { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String name; String description; BigDecimal price; // 共享主键,必须存在关联记录,立即加载 @OneToOne(optional = false, fetch = FetchType.EAGER) @MapsId @JoinColumn(name = "id") Allergens allergens; // 标准getter、setter方法 // 可封装扁平化getter,比如getPeanuts()直接返回allergens.getPeanuts() }
该方案也会自动生成内连接查询,结果符合你的预期。
内容的提问来源于stack exchange,提问作者user1895917
相关产品推荐
相关产品推荐

