OneToMany JPA该用法是否有效?是否我误解了相关概念?
现有代码的核心错误
- JPA关联注解(
@ManyToOne/@OneToMany等)只能标注在实体类类型的属性上,不能标注在主键值类型(比如Long)的字段上,你把@ManyToOne标在Long playerId类的字段上属于完全错误的用法,JPA无法识别该关联。 @OneToMany不能标注在Player的主键id字段上,该注解需要标注在对应关联实体的集合属性上,比如一对多场景下需要在Player类中定义List<Game> games属性,再在该属性上标注注解。
OneToMany是否适配当前场景
单纯的OneToMany关系完全不适合这个场景:OneToMany的语义是「一个Player关联多个Game,但一个Game只能对应一个Player」,和你「单场Game需要关联多个Player」的需求冲突。
你可以根据业务场景选择以下两种实现方案:
方案1:固定玩家数场景,使用多个@ManyToOne关联
如果你的业务确定每场游戏的玩家数量固定(比如最多4人,后续不会扩展),可以用你设想的多字段关联逻辑,但不要存玩家id,直接关联Player实体:
@Entity public class Game { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long gameId; @ManyToOne @JoinColumn(name = "player1_id", nullable = false) private Player player1; @ManyToOne @JoinColumn(name = "player2_id", nullable = false) private Player player2; @ManyToOne @JoinColumn(name = "player3_id") private Player player3; @ManyToOne @JoinColumn(name = "player4_id") private Player player4; }
这种方案不需要中间表,查询逻辑简单,创建Game对象时直接校验非空的player数量≥2即可。
方案2:非固定玩家数场景,使用@ManyToMany关联
如果玩家数量不固定,或者后续有扩展人数的可能,推荐使用多对多关联,Game侧维护玩家集合:
@Entity public class Game { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long gameId; @ManyToMany @JoinTable( name = "game_player_relation", joinColumns = @JoinColumn(name = "game_id"), inverseJoinColumns = @JoinColumn(name = "player_id") ) private List<Player> players; } @Entity public class Player { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String firstName; private String lastName; private String email; // 若不需要从玩家侧查询参与过的所有游戏,可省略下方反向关联配置 @ManyToMany(mappedBy = "players") private List<Game> participatedGames; }
这种方案扩展性极强,创建Game对象时校验players集合的大小≥2、且集合内无重复玩家即可满足需求。
内容的提问来源于stack exchange,提问作者Tim Hudson
相关产品推荐
相关产品推荐

