2012-09-24 10 views
5

Mam następujący dość prosty jednego do wielu relacji:Hibernate nie usuwać sieroty na OneToMany

Zespół posiada zestaw graczy:

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

i każdy ma unikatowy identyfikator & nazwę gracza.

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

biegnę bardzo prosty kod:

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

I uzyskać następujące zgodnie z oczekiwaniami:

  • Hibernate: select team_.id, team_.team_name jak team2_0_ z drużyny team_ gdzie team_.id =?
  • Hibernate: wybierz player_.id, player_.player_name jako player2_1_ od gracza PLAYER_, gdzie player_.id =?
  • Hibernate: wybierz player_.id, player_.player_name jako player2_1_ od gracza PLAYER_, gdzie player_.id =?
  • Hibernate: wybierz player_.id, player_.player_name jako player2_1_ od gracza PLAYER_, gdzie player_.id =?
  • hibernacji: wstawić do zespołu (TEAM_NAME, ID) wartości
  • hibernacji (,?) Wstawić do odtwarzacza (PLAYER_NAME, ID) wartości
  • hibernacji (,?) Wstawić do odtwarzacza (PLAYER_NAME, id) wartości (?,?)
  • Hibernacja: wstaw do wartości: ODTWARZACZ (player_name, id) (?,?)
  • Hibernate: zaktualizuj zestaw PLAYER TEAM_ID =? gdzie id =? Hibernate: zaktualizuj zestaw PLAYER TEAM_ID =? gdzie id =? Hibernate: zaktualizuj zestaw PLAYER TEAM_ID =? gdzie id =?

Później robię:

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

i oczekują gracze sieroce mają zostać usunięte, ale pojawia się:

  • Hibernate: select team_.id, team_.team_name jak team2_0_ z drużyny team_ where team_.id =?
  • Hibernate: wybierz player_.id, player_.player_name jako player2_1_ od gracza PLAYER_, gdzie player_.id =?
  • Hibernate: wybierz player_.id, player_.player_name jako player2_1_ od gracza PLAYER_, gdzie player_.id =?
  • Hibernate: zaktualizuj zestaw PLAYER TEAM_ID = null gdzie TEAM_ID =?
  • Hibernate: zaktualizuj zestaw PLAYER TEAM_ID =? gdzie id =?
  • Hibernate: zaktualizuj zestaw PLAYER TEAM_ID =? gdzie id =?

Co pozostawia gracza osieroconego (identyfikator = 3) rozłączony, ale nie usunięty ... Jakieś pomysły, co robię źle?

+1

Co robi metoda 'createTeam()'? – dcernahoschi

+0

tworzy drużynę z graczami –

+0

Może to być powiązane lub nie, ale testujemy ją na HSQL –

Odpowiedz

0

Dodaj atrybut mappedBy w relacji obu podmiotów.

Dodaj zespół w odtwarzaczu.

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

I MappeedBy w odtwarzaczu.

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

W przypadku relacji 1-TO-M dziecko powinno mieć odniesienie do rodzica. Następnie hibernacja wewnętrznie wykorzystuje identyfikator rodzica jako obcy w tabeli podrzędnej.

Twój stół dziecko będzie mieć te 3 kolumny:

id , player_name,team_id 
+1

Nie ma powodu, aby powiązanie było dwukierunkowe.W każdym razie, w powiązaniu dwukierunkowym, tylko jedna strona musi mieć atrybut mappedBy, ponieważ oznacza: "przejdź do mapowania powiązania po drugiej stronie". –

3

Jeśli chcesz, że gracze są usuwane jako delete-sieroty, trzeba, że ​​gracze tracą odniesienie do zespołu i zapisać zespół.

Co robisz jest następujący:

  • Utwórz nowy zespół obiektów.
  • Nakarm zespół z 3 graczy
  • Utrzymują

Po tym, każdy wiersz gracz będzie zawierać FK do zespołu (id = 1).

Następnie kod tworzy nową drużynę o tym samym id i karmi 2 graczy i trwa.

W tym momencie nadal będzie graczem w DB, że odniesienia do zespołu 1.

z mojego POV każdy inny obiekt biznesowy powinien mieć swój własny klucz biznesowego. Jeśli chcesz nadpisać graczy z drużyny 1, powinieneś najpierw pobrać drużynę, gdzie id = 1, a następnie nakarmić graczy.

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, kolejna porada. Nie zezwalaj na bezpośrednią modyfikację odtwarzaczy, która może prowadzić do błędów Hibernacji takich jak "Nie zmieniaj odniesienia do kolekcji ...". Zamiast setPlayers() dodać metody addPlayer() i removePlayer()

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

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

Również zbiór jest zmienny, więc upewnij getPlayers(), aby powrócić do niemodyfikowalne kolekcję:

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

nadzieję, że to rzuca światło :)

1

Możesz użyć tego znacznika: @ org.hibernate.annotations.Cascade (value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN). Więc dostaniesz:

@OneToMany (kaskada = {}, orphanRemoval CascadeType.ALL = true) @ org.hibernate.annotations.Cascade (wartość = org.hibernate.annotations.CascadeType.DELETE_ORPHAN) @JoinColumn (nazwa = "TEAM_ID")

Powiązane problemy