【发布时间】:2021-03-04 18:21:12
【问题描述】:
我正在尝试创建一个非常简单的 Spring Boot 应用程序来存储运动数据。
它有两个实体:玩家和锦标赛。但是,我想存储每个玩家在每个锦标赛中的排名。
为此,我创建了以下 ER 图。联结表PlayerPlacement_map 包含一个关系属性placement,用于存储玩家在锦标赛中的位置:
我已按照本指南了解如何映射 Players 和 Tournament 之间的关系,并将这两个表中的 Id 作为连接表中的复合键,称为 PlayerPlacementMap:https://www.baeldung.com/jpa-many-to-many
这给了我以下课程:
Player.java(Tournament.java 遵循类似的模式 - 为简洁起见)
@Entity
@Table(name = "players")
public class Player {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id", updatable = false, nullable = false)
private long id;
@Column(name = "Name")
private String name;
@ManyToMany
@JoinTable(
name = "PlayerTournament_map",
joinColumns = @JoinColumn(name = "Player_Id"),
inverseJoinColumns = @JoinColumn(name = "Tournament_Id"))
Set<Tournament> attendedTournaments;
@OneToMany(mappedBy = "player")
Set<PlayerPlacement> placements;
//getters, constructors - left out for brevity
}
PlayerPlacementKey.java(制作可嵌入的复合键类)
@Embeddable
public class PlayerPlacementKey implements Serializable {
@Column(name = "Player_Id")
long playerId;
@Column(name = "Tournament_Id")
long tournamentId;
//getters, setters, constructors, equals, hashcode - left out for brevity
}
PlayerPlacement.java(联结表)
@Entity
@Table(name = "PlayerPlacement_map")
public class PlayerPlacement {
@EmbeddedId
PlayerPlacementKey id;
@ManyToOne
@MapsId("PlayerId")
@JoinColumn(name = "Player_Id")
Player player;
@ManyToOne
@MapsId("TournamentId")
@JoinColumn(name = "Tournament_Id")
Tournament tournament;
int placement;
//constructors - left out for brevity
}
我有存储库用于玩家、锦标赛和玩家位置。玩家和锦标赛存储库独立运行良好,我可以通过 @RestController 对 MSSQL 数据库执行 CRUD 操作。
这是玩家放置的存储库:
@Repository
public interface PlayerPlacementRepository extends JpaRepository<PlayerPlacement, PlayerPlacementKey>
{}
对于联结表,我做了一个PlayerPlacementController:
@RestController
public class PlayerPlacementController {
@Autowired
private PlayerPlacementRepository playerPlacementRepository;
@PostMapping("/playerplacement")
public PlayerPlacement addPlayerPlacement(@RequestBody PlayerPlacement playerPlacement) {
return playerPlacementRepository.save(playerPlacement);
}
}
最后,问题来了:当我调用/"playerplacement" 端点时,我收到以下错误:
org.hibernate.id.IdentifierGenerationException: null id generated for:class com.testproject.learning.model.PlayerPlacement
我认为我已经很好地迁移了数据库,但为了安全起见,这是我对联结表的迁移:
CREATE TABLE PlayerPlacement_map (
PlayerId Bigint NOT NULL,
TournamentId Bigint NOT NULL,
Placement int
CONSTRAINT PK_PlayerPlacement NOT NULL IDENTITY(1,1) PRIMARY KEY
(
PlayerId,
TournamentId
)
FOREIGN KEY (PlayerId) REFERENCES Players (Id),
FOREIGN KEY (TournamentId) REFERENCES Tournaments (Id)
);
我一直无法弄清楚我做错了什么。感谢我收到的所有帮助和指点 - 在此先感谢。
编辑: 在用户 Alex V. 的帮助下取得了进展,但我现在遇到了一个新问题。
我进行以下 JSON 调用:
{
"player":
{
"name":"John Winther"
},
"tournament":
{
"name":"Spring Boot Cup 2020"
},
"placement":3
}
我自己没有设置id(复合键)——我猜它应该由框架的某些东西来处理?无论如何,当我在调试模式下进行此调用时,我会在端点中设置以下 调试变量:
但是,它会导致以下错误:
java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null,这可能是指我PlayerPlacementKey.java中的equals-method(?):
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlayerPlacementKey)) return false;
PlayerPlacementKey that = (PlayerPlacementKey) o;
return playerId == that.playerId &&
tournamentId == that.tournamentId;
}
希望有人能再一次把我推向正确的方向。
【问题讨论】:
-
你应该在
equals方法中添加:if(null == o) return false; -
嘿@alexvaluiskyi 非常感谢。我试图将它添加到
equals-方法的第一行,但不幸的是它返回了相同的错误消息。不过,我真的很感谢您的帮助,非常感谢。 -
据我了解,您尝试持久化
PlayerPlacement包含Player和Tournament没有持久化到数据库?如果是这样,您必须为每个关系添加适当的级联参数:howtodoinjava.com/hibernate/hibernate-jpa-cascade-types/…。 -
@alexvaluiskyi 再次感谢 Alex。我将彻底查看文档。感谢您给予我的所有帮助
标签: java spring-boot hibernate orm composite-key