一个行为类似于@Entity和@Embeddable的类

我在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 playerList = new ArrayList(); } @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类中使用CascadeType.PERSIST与@Entity而不是@Embeddable来保存团队和玩家(单向关系)吗?

请记住,在保存之前需要分配COMPOUND主键,但Team的标识符和PlayerList索引位置可以扮演Player的复合主键的角色

问候,

以下解决方案显示了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 players = new ArrayList(); 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 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 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]]] 

最后一行显示了TeamPlayertoString ,它显示了如何分配数字(列表的索引)。 其他实体可以引用播放器(通过team_id和player_idx)。

我觉得你犯了一些错误。

@Embedded是一种表示由表中选定字段构成的对象/组件的方法。 您可以使用它来表示复合键,但您还需要使用@EmbeddedId。

看看你想要实现的目标,我觉得你可以通过更简单的映射实现目标。 (为简洁起见,省略了一些部分)

 @Entity public class Team { @OneToMany(mappedBy="team") private List playerList = new ArrayList(); } @Enity public class Player { @ManyToOne @JoinColumn(name="TEAM_ID") private Team team; } 

如果Player是连接/链接表,您可以使用@Embedded静态类来表示组合键,有关此内容的更多信息,请参阅Java Persistence with JPA一书。