5

我有以下非常简单的一对多关系:

球队有一组球员:

@Entity(name = "TEAM")
@Access(AccessType.PROPERTY)
public class Team{
    private Integer id;
    private String name;
    private Set<Player> players ;

    @Id
    @Column(name = "id")
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "team_name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(cascade = {CascadeType.ALL},orphanRemoval=true)
    @JoinColumn(name = "TEAM_ID")
    public Set<Player> getPlayers() {
        return players;
    }

    public void setPlayers(Set<Player> players) {
        this.players = players;
    }       
}

每个玩家都有一个唯一的 id 和 name。

@Entity(name = "PLAYER")
@Access(AccessType.PROPERTY)
public class Player implements Serializable{

    private int id;
    private String name;

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "player_name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object obj) {
    return id == ((Player)obj).id;
    }
    @Override
    public int hashCode() {
        return id;
    }
}

我运行一个非常简单的代码:

Team team = createTeam(3) // creates team with 3 players ids={1,2,3}
session.saveOrUpdate(team);
...

private Team createTeam(int players) {
    Team team = new Team();
    team.setName("Bears");
    team.setId(1);
    for(int i=1 ; i<=players; ++ i){
        Player player = new Player();
        player.setId(i);
        player.setName("Player"+i);
        team.addPlayer(player);
    }
    return team;
}

我得到以下预期:

  • 休眠:从 TEAM team_ 中选择 team_.id, team_.team_name 作为 team2_0_ where team_.id=?
  • 休眠:从 PLAYER player_ where player_.id=? 中选择 player_.id, player_.player_name 作为 player2_1_
  • 休眠:从 PLAYER player_ where player_.id=? 中选择 player_.id, player_.player_name 作为 player2_1_
  • 休眠:从 PLAYER player_ where player_.id=? 中选择 player_.id, player_.player_name 作为 player2_1_
  • Hibernate:插入 TEAM (team_name, id) 值 (?, ?)
  • Hibernate:插入 PLAYER (player_name, id) 值 (?, ?)
  • Hibernate:插入 PLAYER (player_name, id) 值 (?, ?)
  • Hibernate:插入 PLAYER (player_name, id) 值 (?, ?)
  • 休眠:更新 PLAYER 设置 TEAM_ID=? 哪里id=?休眠:更新 PLAYER 设置 TEAM_ID=? 哪里id=?休眠:更新 PLAYER 设置 TEAM_ID=? 哪里id=?

然后我做:

Team team = createTeam(2) // creates team with 2 player ids={1,2}
session.saveOrUpdate(team);

并期望删除孤儿玩家,但我得到:

  • 休眠:从 TEAM team_ 中选择 team_.id, team_.team_name 作为 team2_0_ where team_.id=?
  • 休眠:从 PLAYER player_ where player_.id=? 中选择 player_.id, player_.player_name 作为 player2_1_
  • 休眠:从 PLAYER player_ where player_.id=? 中选择 player_.id, player_.player_name 作为 player2_1_
  • 休眠:更新 PLAYER 设置 TEAM_ID=null where TEAM_ID=?
  • 休眠:更新 PLAYER 设置 TEAM_ID=? 哪里id=?
  • 休眠:更新 PLAYER 设置 TEAM_ID=? 哪里id=?

这使孤儿播放器(id = 3)断开连接但没有被删除......有什么想法我做错了吗?

4

3 回答 3

3

如果您希望将球员作为删除孤儿删除,则需要球员失去对球队的引用并保存球队。

您正在做的是以下内容:

  • 创建一个新的对象团队。
  • 用 3 名球员养活球队
  • 坚持

之后,每个玩家行将包含一个 FK 到团队 (id=1)。

然后代码创建一个具有相同 id 的新团队,并养活 2 名玩家并坚持下去。

那时,DB 中仍然会有一名球员引用球队 1。

从我的 POV 来看,每个不同的业务对象都应该有自己的业务密钥。如果你想覆盖队 1 的球员,你应该首先检索 id = 1 的球队,然后喂球员。

private Team createTeam(int players) {
    Team team = session.get(Team.class, 1);
    if (team == null) {
       team = new Team();
       team.setName("Bears");
       team.setId(1);
    }
    team.clearPlayers();

    for(int i=1 ; i<=players; ++ i){
        Player player = new Player();
        player.setId(i);
        player.setName("Player"+i);
        team.addPlayer(player);
    }
    return team;
}

// Team.java
private void clearPlayers() {
   players.clear();
}

顺便说一句,另一个建议。不允许直接修改您的播放器,这可能会导致 HibernateErrors,例如“Don't change the reference to a collection...”。代替 setPlayers(),添加方法addPlayer()removePlayer()

private void adddPlayer(Player player) {
   player.setTeam(this);
   players.add(player);
}

private void removePlayer(Player player) {
   player.setTeam(null);
   players.remove(player);
}

此外,集合是可变的,所以让 getPlayers() 返回一个不可修改的集合:

private Set<Player> getPlayers() {
   return Collections.unmodifiableSet(players);
}

希望这能有所启发:)

于 2012-10-03T21:09:28.847 回答
1

你可以使用这个标签:@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)。所以你得到:

@OneToMany(cascade = {CascadeType.ALL},orphanRemoval=true) @org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN) @JoinColumn(name = "TEAM_ID")

于 2013-04-23T14:40:11.157 回答
0

在两个实体的关系中添加 mappedBy 属性。

在播放器中添加团队。

// in Player.java
@ManyToOne(mappedBy="players")
private Team team;

和 Player 中的 MappeedBy。

//In Team.java
@OneToMany(cascade = {CascadeType.ALL},orphanRemoval=true,mappedBy="team")
    @JoinColumn(name = "TEAM_ID")
    public Set<Player> getPlayers() {
        return players;
    }

当您有 1-TO-M 关系时,孩子应该有其父母的参考。然后休眠在内部使用父ID作为子表中的外部。

您的子表将具有以下 3 列:

id , player_name,team_id
于 2012-09-27T12:28:40.917 回答