我有以下非常简单的一对多关系:
团队有一组球员:
@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和名。
@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 = createTeam(2) // creates team with 2 player ids={1,2}
session.saveOrUpdate(team);
并期望孤儿玩家被删除,但我得到:
让孤儿播放器(id = 3)断开但未删除... 我有什么想法吗?
答案 0 :(得分: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();
}
BTW,另一个建议。不允许直接修改您的播放器,这可能导致HibernateErrors,例如我们“不要更改对集合的引用......”。而不是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);
}
希望这能有所启发:)
答案 1 :(得分: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”)
答案 2 :(得分:0)
在两个实体的关系中添加mappedBy属性。
在玩家中添加团队。
// in Player.java
@ManyToOne(mappedBy="players")
private Team team;
MappeedBy in Player。
//In Team.java
@OneToMany(cascade = {CascadeType.ALL},orphanRemoval=true,mappedBy="team")
@JoinColumn(name = "TEAM_ID")
public Set<Player> getPlayers() {
return players;
}
当你有1对M的关系时,孩子应该有一个父母的参考。然后hibernate在内部使用父的id作为子表中的外来函数。
您的子表将包含以下3列:
id , player_name,team_id