Spring中EmbeddedId关联Race与PersonRace的Join方式问题
问题:Spring JPA构建Race与PersonRace关联时抛出表不存在错误
在数据库中,person_race和race是核心表,使用Spring JPA构建关联关系时,调用findAll接口抛出错误:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "race_person_races" does not exist
相关实体类代码如下:
PersonRace.java
@Entity @NoArgsConstructor @AllArgsConstructor @Getter @Setter @ToString public class PersonRace { @EmbeddedId @NotNull private PersonRaceId personRaceId; @Column(name = "player_class") @NotNull private String playerClass; @Column(name = "motorbike_model") @NotNull private String motorbikeModel; @NotNull private boolean confirmed; @NotNull @Column(name = "number_in_race") private long numberInRace; }
PersonRaceId.java
@Embeddable @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class PersonRaceId implements Serializable { @OneToOne @JoinColumn(name = "race_id") @NotNull private Race race; @OneToOne @NotNull @JoinColumn(name = "person_id") private Person person; }
Race.java
@Entity @NoArgsConstructor @Getter @Setter @ToString public class Race { @Id @Column(name = "race_id") @GeneratedValue(strategy = GenerationType.IDENTITY) @NotNull private Long id; @Column(name = "max_players") @NotNull private Integer maxPlayers; @NotNull private String description; @NotNull private String location; @NotNull private LocalDateTime date; @NotNull private String state; @ManyToOne @NotNull @JoinColumn(name = "event_id") private RaceEvent raceEvent; @OneToMany @JoinColumn(name = "lap_id") private List<Lap> laps; @OneToMany // 问题代码 @PrimaryKeyJoinColumns(value = { @PrimaryKeyJoinColumn(name = "race_id", referencedColumnName = "race_id"), @PrimaryKeyJoinColumn(name = "person_id", referencedColumnName = "person_id") }) private List<PersonRace> personRaces; public Race(@NotNull Long id, @NotNull Integer maxPlayers, @NotNull String description, @NotNull String location, @NotNull LocalDateTime date, @NotNull String state, @NotNull RaceEvent raceEvent, List<Lap> laps, List<PersonRace> personRaces) { this.id = id; this.maxPlayers = maxPlayers; this.description = description; this.location = location; this.date = date; this.state = state; this.raceEvent = raceEvent; this.laps = laps; this.personRaces = personRaces; } }
解决方案
1. 修正复合主键中的映射方式
复合主键类PersonRaceId不能直接用实体关联注解,需改用基本类型映射数据库主键字段:
@Embeddable @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class PersonRaceId implements Serializable { @Column(name = "race_id") @NotNull private Long raceId; @Column(name = "person_id") @NotNull private Long personId; }
2. 在PersonRace中建立与Race、Person的关联
通过@MapsId注解将实体关联映射到复合主键的对应字段:
@Entity @NoArgsConstructor @AllArgsConstructor @Getter @Setter @ToString public class PersonRace { @EmbeddedId @NotNull private PersonRaceId personRaceId; @ManyToOne @MapsId("raceId") // 关联复合主键中的raceId字段 @JoinColumn(name = "race_id") @NotNull private Race race; @ManyToOne @MapsId("personId") // 关联复合主键中的personId字段 @JoinColumn(name = "person_id") @NotNull private Person person; @Column(name = "player_class") @NotNull private String playerClass; @Column(name = "motorbike_model") @NotNull private String motorbikeModel; @NotNull private boolean confirmed; @NotNull @Column(name = "number_in_race") private long numberInRace; }
3. 修正Race中的@OneToMany关联
使用mappedBy指定关联关系由PersonRace中的race字段维护,避免JPA生成不存在的中间表:
@OneToMany(mappedBy = "race", fetch = FetchType.LAZY) private List<PersonRace> personRaces;
错误原因说明
- 原代码中
PersonRaceId直接用@OneToOne关联实体,违反JPA复合主键规范,复合主键应使用基本数据类型映射数据库字段。 Race中误用@PrimaryKeyJoinColumns,导致JPA错误认为需要生成中间表race_person_races,实际person_race本身就是关联表,需通过mappedBy指定反向关联。
内容的提问来源于stack exchange,提问作者Ser
相关产品推荐
相关产品推荐

