spring引导:创建复合键和多对多关系

ozxc1zmp  于 2021-07-11  发布在  Java
关注(0)|答案(1)|浏览(455)

我试图创建一个非常简单的spring-boot应用程序来存储运动数据。
它有两个实体:玩家和锦标赛。但是,我想存储每个球员在每个锦标赛中的位置。
为此,我创建了下面的er图。连接表 PlayerPlacement_map 包含关系属性 placement 用于存储玩家在锦标赛中的位置:

我遵循了这个指南,了解了如何Map玩家和锦标赛之间的关系,将这两个表中的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操作。
这是playerplacement的存储库:

@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)
);

我还没弄清楚我做错了什么。我感谢所有的帮助和指点,我收到-提前感谢。
编辑:在用户alexv的帮助下已经取得了进展,但是我现在遇到了一个新问题。
我进行以下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 ,可能是指我的 equals -中的方法 PlayerPlacementKey.java (?):

@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;
}

希望有人能再把我推向正确的方向。

yhxst69z

yhxst69z1#

您的实体 playerId 字段注解为 @Column(name = "Player_Id") ,但数据库表包含 PlayerId 列而不是 Player_Id . 同样的情况 tournamentId , player , tournament 领域。 @MapsId("TournamentId") 必须包含 @EmbededId 类字段名 tournamentId 而不是 TournamentId . 这意味着该字段由嵌入的id字段Map tournamentId .

@ManyToOne
@MapsId("tournamentId")
@JoinColumn(name = "tournamentId")
Tournament tournament;

同样的问题 @MapsId("PlayerId") .

相关问题