我在Team和Player类之间有单向@OneToMany关系。我想在你的玩家中保存一个Team对象。玩家的标识符由Team外键和列表索引组成,如下所示。我有这样的映射,因为我需要保存团队和你的玩家同时吃饭。
@Entity
public class Team {
@Id
@GeneratedValue
private Integer id;
@CollectionOfElements
@JoinTable(
name="PLAYER",
joinColumns=@JoinColumn(name="TEAM_ID"))
@IndexColumn(name="PLAYER_INDEX")
private List<Player> playerList = new ArrayList<Player>();
}
@Embeddable
public class Player {
// Player's getter's and setter's
}
所以,如果我使用以下
Team team = new Team();
team.getPlayerList().add(new Player());
team.getPlayerList().add(new Player());
session.save(team); // It works!
无论你使用@CollectionsOfElements,Player类需要@Embeddable注释,而不是@Entity,都会发生这种情况。 JPA不允许@Entity和@Embeddable同时使用。玩家也是@Entity--它与其他实体有关系。
有人知道我可以通过在Player类中使用@Entity的CascadeType.PERSIST而不是@Embeddable来保存团队和播放器(单向关系)吗?
请记住,在保存之前需要分配COMPOUND主键,但Team的标识符和PlayerList索引位置可以扮演Player的复合主键
的问候,
答案 0 :(得分:6)
以下解决方案显示了Player的复合键,其中包括Team和该团队中玩家列表中的位置。从团队到玩家保存级联。
<强> 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();
}
}
以下测试:
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);
给出以下日志输出:
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]]]
最后一行显示toString
和Team
的{{1}},其中显示了如何分配号码(列表的索引)。其他实体可以引用播放器(通过team_id和player_idx)。
答案 1 :(得分:0)
我觉得你犯了一些错误。
@Embedded是一种表示由表中选定字段构成的对象/组件的方法。您可以使用它来表示复合键,但您还需要使用@EmbeddedId。
看看你想要实现的目标,我觉得你可以通过更简单的映射实现目标。 (为简洁起见省略了一些部分)
@Entity
public class Team {
@OneToMany(mappedBy="team")
private List<Player> playerList = new ArrayList<Player>();
}
@Enity
public class Player {
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
}
如果Player是连接/链接表,您可以使用@Embedded静态类来表示复合键,有关此内容的详细信息,请参阅Java持久性和JPA一书。