Класс, который ведет себя как @Entity и @Embeddable - PullRequest
5 голосов
/ 23 июня 2009

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

@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 одновременно. Player также является @Entity - у него есть отношения с другими объектами.

Есть ли у кого-нибудь идея о том, чтобы я мог сохранить команду и игрока (ONE WAY RELATIONSHIP), используя CascadeType.PERSIST с @Entity в классе Player вместо @Embeddable?

Помните, что первичный ключ COMPOUND должен быть назначен перед сохранением, но идентификатор команды и позиция индекса PlayerList могут играть роль составного первичного ключа Player

С уважением,

Ответы [ 2 ]

6 голосов
/ 27 июня 2009

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

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

0 голосов
/ 23 июня 2009

Вы допустили некоторые ошибки, которые я чувствую.

@ 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 Persistence с JPA для получения дополнительной информации об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...