2009-06-22 2 views
5

У меня есть одностороннее отношение @OneToMany между классом Team и Player. Я хотел бы сохранить объект Team среди ваших игроков. Идентификатор игрока IS COMPOUND по команде внешнего ключа и индекса списка следующим образом. У меня есть сопоставление, подобное этому, потому что мне нужно сохранить команду, и ваши игроки ели одновременно.Класс, который ведет себя как @Entity и @Embeddable

@Entity 
public class Team { 

    @Id 
    @GeneratedValue 
    private Integer id; 

    @CollectionOfElements 
    @JoinTable(
     name="PLAYER", 
     [email protected](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, класс игрока нужен @Embeddable аннотацию, а не @Entity. JPA не позволяет одновременно использовать @Entity и @Embeddable. Игрок также является @Entity - он имеет отношения с другими объектами.

У кого-то есть идея о том, что я мог бы сэкономить команду и игрока (ОДИН ПУТЬ), используя CascadeType.PERSIST с @Entity в классе Player вместо @Embeddable?

Помните, что СОЕДИНЕНИЕ первичный ключ должен быть назначен перед сохранением, но идентификатор и PlayerList позиции индекса команды могли бы играть роль составного первичного ключа

относительно игрока,

ответ

6

В приведенном ниже решении показан составной ключ для игрока, который состоит из команды и позиции в списке игроков в этой команде. Сохраняет каскад от команды к игрокам.

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 и Player, который показывает, как номера присваиваются (индекс списка). Другие объекты могут ссылаться на Игрока (by team_id и player_idx).

+0

Поздравления, Maarten. Хороший ответ. –

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; 

} 

Если игрок является объединение/таблицы ссылок вы можете использовать @Embedded статического класс для представления составного ключа, можно найти в книге Java Persistence с JPA для получения дополнительной информации по этому вопросу.

Смежные вопросы