The below solution shows a composite key for Player that consists of Team and the position in the list of players in that team. Saves cascade from team to players.
Team.java
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Version;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.hibernate.annotations.IndexColumn;
@Entity
public class Team implements Serializable {
@Id @GeneratedValue private Long id;
@Version private int version;
@OneToMany(cascade=CascadeType.ALL, mappedBy="id.team")
@IndexColumn(name="PLAYER_IDX")
private List<Player> players = new ArrayList<Player>();
private String name;
protected Team() {}
public Team(String name) {
this.name = name;
}
public boolean addPlayer(Player player) {
boolean result = players.add(player);
if (result) {
player.setPlayerId(new PlayerId(this, players.size() - 1));
}
return result;
}
public List<Player> getPlayers() {
return players;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("name", name).append("players", players).toString();
}
}
Player.java
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Version;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
@Entity
public class Player implements Serializable {
@Id private PlayerId id;
@Version private int version;
void setPlayerId(PlayerId id) {
this.id = id;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("number", id.getNumber()).toString();
}
}
PlayerId.java
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
import org.apache.commons.lang.builder.HashCodeBuilder;
@Embeddable
public class PlayerId implements Serializable {
@ManyToOne
private Team team;
@Column(name="PLAYER_IDX", insertable=false, updatable=false)
private int number;
protected PlayerId() {}
PlayerId(Team team, int number) {
this.team = team;
this.number = number;
}
public int getNumber() {
return number;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (obj == this) {
return true;
} if (obj instanceof PlayerId) {
PlayerId other = (PlayerId) obj;
return other.team.equals(this.team) && other.number == this.number;
}
return false;
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(team).append(number).toHashCode();
}
}
This test below:
public void testPersistTeamAndPlayers() throws Exception {
Team team = new Team("My Team");
team.addPlayer(new Player());
team.addPlayer(new Player());
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration.addAnnotatedClass(Team.class);
configuration.addAnnotatedClass(Player.class);
configuration.configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session;
session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(team);
transaction.commit();
session.close();
session = sessionFactory.openSession();
@SuppressWarnings("unchecked") List<Team> list = session.createCriteria(Team.class).list();
assertEquals(1, list.size());
Team persisted = list.get(0);
System.out.println(persisted);
gives the following log output:
12:37:17,796 DEBUG [SchemaExport, SchemaExport.execute]
create table Player (
PLAYER_IDX integer not null,
version integer not null,
team_id bigint,
primary key (PLAYER_IDX, team_id)
)
12:37:17,796 DEBUG [SchemaExport, SchemaExport.execute]
create table Team (
id bigint generated by default as identity (start with 1),
name varchar(255),
version integer not null,
primary key (id)
)
12:37:17,796 DEBUG [SchemaExport, SchemaExport.execute]
alter table Player
add constraint FK8EA38701AA5DECBA
foreign key (team_id)
references Team
12:37:17,812 INFO [SchemaExport, SchemaExport.importScript] Executing import script: /import.sql
12:37:17,812 INFO [SchemaExport, SchemaExport.execute] schema export complete
12:37:17,859 DEBUG [SQL, SQLStatementLogger.logStatement]
insert
into
Team
(id, name, version)
values
(null, ?, ?)
12:37:17,875 DEBUG [SQL, SQLStatementLogger.logStatement]
call identity()
12:37:17,875 DEBUG [SQL, SQLStatementLogger.logStatement]
select
player_.PLAYER_IDX,
player_.team_id,
player_.version as version1_
from
Player player_
where
player_.PLAYER_IDX=?
and player_.team_id=?
12:37:17,890 DEBUG [SQL, SQLStatementLogger.logStatement]
select
player_.PLAYER_IDX,
player_.team_id,
player_.version as version1_
from
Player player_
where
player_.PLAYER_IDX=?
and player_.team_id=?
12:37:17,890 DEBUG [SQL, SQLStatementLogger.logStatement]
insert
into
Player
(version, PLAYER_IDX, team_id)
values
(?, ?, ?)
12:37:17,890 DEBUG [SQL, SQLStatementLogger.logStatement]
insert
into
Player
(version, PLAYER_IDX, team_id)
values
(?, ?, ?)
12:37:17,906 DEBUG [SQL, SQLStatementLogger.logStatement]
select
this_.id as id0_0_,
this_.name as name0_0_,
this_.version as version0_0_
from
Team this_
12:37:17,937 DEBUG [SQL, SQLStatementLogger.logStatement]
select
players0_.team_id as team3_1_,
players0_.PLAYER_IDX as PLAYER1_1_,
players0_.PLAYER_IDX as PLAYER1_1_0_,
players0_.team_id as team3_1_0_,
players0_.version as version1_0_
from
Player players0_
where
players0_.team_id=?
Team[name=My Team,players=[Player[number=0], Player[number=1]]]
The last line shows the toString
for Team
and Player
, which shows how the numbers are assigned (the index of the list). Other entities can refer the Player (by team_id and player_idx).