2009-06-22 20 views
5

Tengo una relación unidireccional @OneToMany entre una clase de equipo y jugador. Me gustaría guardar un objeto Team entre tus Jugadores. El identificador del jugador está COMPUESTO por la clave foránea del equipo y el índice de la lista de la siguiente manera. Tengo un mapa como este porque necesito guardar el equipo y tus jugadores comieron al mismo tiempo.Una clase que se comporta como @Entity y @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 

} 

Así que si yo uso el siguiente

Team team = new Team(); 

team.getPlayerList().add(new Player()); 
team.getPlayerList().add(new Player()); 

session.save(team); // It works! 

Ocurre si se utiliza @CollectionsOfElements, clase Player es necesario un @Embeddable anotación, no un @Entity. JPA no permite @Entity y @Embeddable al mismo tiempo. El jugador también es un @Entity, tiene una relación con otras entidades.

¿Alguien tiene una idea acerca de que podría salvar a un Equipo y un Jugador (UNA MANERA DE RELACIÓN) utilizando CascadeType.PERSIST con @Entity en la clase Player en lugar de @Embeddable?

Recuerde que clave compuesta primaria debe ser asignado antes de guardar, pero la posición del índice identificador y playerlist del equipo podría desempeñar el papel de los compuestos primarios clave

respecto del jugador,

Respuesta

6

La siguiente solución muestra una clave compuesta para Jugador que consiste en Equipo y la posición en la lista de jugadores en ese equipo. Guarda la cascada del equipo a los jugadores.

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(); 
    } 

} 

por debajo de este ensayo:

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); 

da la siguiente salida del registro:

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]]] 

La última línea muestra el toString para Team y Player, que muestra cómo los números se asignan (el índice de la lista). Otras entidades pueden referir al jugador (por team_id y player_idx).

+0

Felicidades, Maarten. Buena respuesta. –

0

Usted ha hecho algunos errores que siento.

@Embedded es una forma de representar un objeto/componente hecho desde los campos seleccionados en la tabla. Puede usarlo para representar claves compuestas pero también necesita usar @EmbeddedId.

Mirando lo que está tratando de lograr, creo que puede lograrlo con un mapeo mucho más simple. (algunas partes omitidas por razones de brevedad)

@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; 

} 

Si el jugador es una tabla de unión/enlace se puede utilizar una clase estática @Embedded para representar la clave compuesta, ver el libro de persistencia de Java con APP para más información sobre esto.

Cuestiones relacionadas