Hibernate不会删除OneToMany上的孤儿 [英] Hibernate does not delete orphans on OneToMany

查看:103
本文介绍了Hibernate不会删除OneToMany上的孤儿的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



团队有一组玩家:

 @Entity(name =TEAM)
@Access(AccessType.PROPERTY)
public class Team {
private Integer id;
私人字符串名称;
私人设置< Player>球员;

@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(){
返回玩家;
}

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

每位玩家都有独特的ID&名称。

  @Entity(name =PLAYER)
@Access(AccessType.PROPERTY)
公共类Player实现Serializable {

private int id;
私人字符串名称;

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

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

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

 团队团队= createTeam(3)//创建包含3名玩家的团队ids = {1,2,3} 
session.saveOrUpdate (球队);
...

私人团队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);
}
返回团队;
}

我得到以下预期结果:


  • Hibernate:select team_.id,team_.team_name as team2_0_ from team team_ where team_.id =?

  • Hibernate:select player_ .id,player_.player_name as player2_1_ from PLAYER player_ where player_.id =?

  • Hibernate:select player_.id,player_.player_name as player2_1_ from PLAYER player_ where player_.id =?

  • Hibernate:从PLAYER player_选择player_.id,player_.player_name作为player2_1_,其中player_.id =?

  • Hibernate:插入TEAM(team_name, Hibernate:insert into PLAYER(player_name,id)values(?,?)

  • Hibernate:insert into (PLAYER,player_name,id)values(?,?)

  • Hibernate:插入PLAYER(player_name,id)休眠:更新播放器设置TEAM_ID =?其中id =?
    Hibernate:更新PLAYER set TEAM_ID =?其中id =?
    Hibernate:更新PLAYER set TEAM_ID =?其中id =?



然后我会做:

 团队团队= createTeam(2)//用2个玩家创建团队ids = {1,2} 
session.saveOrUpdate(team);

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




  • Hibernate:select team_.id,team_.team_name as team2_0_ from team team_ where team_.id =?

  • Hibernate:select player_。 id,player_.player_name as player2_1_ from PLAYER player_ where player_.id =?

  • Hibernate:select player_.id,player_.player_name as player2_1_ from PLAYER player_ where player_.id =?
  • li>
  • Hibernate:update PLAYER set TEAM_ID = null where TEAM_ID =?

  • Hibernate:更新PLAYER set TEAM_ID =?其中id =?

  • Hibernate:更新PLAYER set TEAM_ID =?其中id =?



让孤立玩家(id = 3)断开连接但未删除...
任何想法我做错了什么?

解决方案

如果你想让玩家被删除为孤儿,你需要玩家松动参考团队和拯救团队。



您在做什么是以下内容:


  • 创建一个新的对象团队。

  • 为3名玩家提供团队

  • 坚持
  • ul>

    然后,每个玩家的行都会包含一个FK给团队(id = 1)。

    一个新的团队,拥有相同的ID,并且支持2名玩家并坚持下去。


    到那时,DB中会有一名玩家参与团队1。 p>

    从我的POV中,每个不同的业务对象都应该有自己的业务密钥。如果你想覆盖第一队的球员,你应该首先检索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();

    (int i = 1; i <= players; ++ i){
    Player player = new Player();
    player.setId(i);
    player.setName(Player+ i);
    team.addPlayer(player);
    }
    返回团队;
    }

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

    顺便说一句,另一个建议。不要直接修改你的播放器,这可能会导致HibernateErrors如us 不要更改对集合的引用......。代替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);





    $ b

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

     私人设定< Player> getPlayers(){
    返回Collections.unmodifiableSet(players);
    }

    希望这可以说明一点:


    I have the following pretty simple one to many relations:

    Team has a Set of players:

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

    And each player has a unique 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;
        }
    }
    

    I run a very simple code:

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

    And I get the following as expected:

    • Hibernate: select team_.id, team_.team_name as team2_0_ from TEAM team_ where team_.id=?
    • Hibernate: select player_.id, player_.player_name as player2_1_ from PLAYER player_ where player_.id=?
    • Hibernate: select player_.id, player_.player_name as player2_1_ from PLAYER player_ where player_.id=?
    • Hibernate: select player_.id, player_.player_name as player2_1_ from PLAYER player_ where player_.id=?
    • Hibernate: insert into TEAM (team_name, id) values (?, ?)
    • Hibernate: insert into PLAYER (player_name, id) values (?, ?)
    • Hibernate: insert into PLAYER (player_name, id) values (?, ?)
    • Hibernate: insert into PLAYER (player_name, id) values (?, ?)
    • Hibernate: update PLAYER set TEAM_ID=? where id=? Hibernate: update PLAYER set TEAM_ID=? where id=? Hibernate: update PLAYER set TEAM_ID=? where id=?

    Then later I do:

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

    And expect the orphan players to be deleted but I get:

    • Hibernate: select team_.id, team_.team_name as team2_0_ from TEAM team_ where team_.id=?
    • Hibernate: select player_.id, player_.player_name as player2_1_ from PLAYER player_ where player_.id=?
    • Hibernate: select player_.id, player_.player_name as player2_1_ from PLAYER player_ where player_.id=?
    • Hibernate: update PLAYER set TEAM_ID=null where TEAM_ID=?
    • Hibernate: update PLAYER set TEAM_ID=? where id=?
    • Hibernate: update PLAYER set TEAM_ID=? where id=?

    Which leaves the orphan player (id=3) disconnected but not deleted... Any ideas what I do wrong?

    解决方案

    If you want that the players are removed as delete-orphan, you need that the players loose the reference to the team and the save the team.

    What you are doing is the following:

    • Create a new object team.
    • Feed the team with 3 players
    • Persist

    After that, each player row will contain a FK to team (id=1).

    Then the code creates a new team, with the same id, and feed 2 players and persist.

    At that point there still will be a player in DB that references to team 1.

    From my POV every different business object should have their own business key. If you want to overwrite the players of team 1, you should first retrieve team where id = 1, and then feed the players.

    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();
    }
    

    BTW, another advice. Don't allow to modify your players directly, that can lead to HibernateErrors such us "Don't change the reference to a collection...". Instead of setPlayers(), add methods for addPlayer() and removePlayer()

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

    Also, a collection is mutable, so make getPlayers() to return a non-modifiable collection:

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

    Hope this sheds some light :)

    这篇关于Hibernate不会删除OneToMany上的孤儿的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆