简体   繁体   English

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

[英]A class that behaves like @Entity and @Embeddable

I have a one way @OneToMany relationship between a Team and Player class. 我在Team和Player类之间有一种@OneToMany关系。 I would like to save a Team object among your Players. 我想在您的玩家之间保存一个Team对象。 Player's identifier IS COMPOUND by Team foreign key and list index as follows. 玩家的标识符由团队外键和列表索引组成,如下所示。 I have a mapping like this one because i need to save Team and your Players ate the same time. 我有一个这样的映射,因为我需要保存Team和您的Players同时吃饭。

@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

}

So if i use the following 所以,如果我使用以下

Team team = new Team();

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

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

It happens whether you use @CollectionsOfElements, Player class need a @Embeddable annotation, not a @Entity. 无论是否使用@ CollectionsOfElements,Player类都需要一个@Embeddable注释,而不是一个@Entity,这会发生。 JPA does not allows @Entity and @Embeddable at the same time. JPA不允许同时使用@Entity和@Embeddable。 Player is also a @Entity - it has relationship with other entities. Player也是@Entity-它与其他实体有关系。

Has someone an idea about i could save a Team and a Player (ONE WAY RELATIONSHIP) by using CascadeType.PERSIST with @Entity in the Player class instead of @Embeddable ? 有没有关于我可以通过在Player类中将CascadeType.PERSIST与@Entity而不是@Embeddable一起使用来保存团队和玩家(单向关系)的想法?

Remember that COMPOUND primary key needs to be assigned before saving but Team's identifier and PlayerList index position could play the role of Player's compound primary key 请记住,在保存之前需要分配COMPOUND主键,但是Team的标识符和PlayerList索引位置可以扮演Player的复合主键

regards, 问候,

The below solution shows a composite key for Player that consists of Team and the position in the list of players in that team. 以下解决方案显示了一个由玩家组成的复合键,该键由团队和该团队中的玩家列表中的位置组成。 Saves cascade from team to players. 从团队到球员节省级联。

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

}

This test below: 此测试如下:

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

gives the following log output: 给出以下日志输出:

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

The last line shows the toString for Team and Player , which shows how the numbers are assigned (the index of the list). 最后一行显示了TeamPlayertoString ,它显示了数字的分配方式(列表的索引)。 Other entities can refer the Player (by team_id and player_idx). 其他实体可以引用玩家(通过team_id和player_idx)。

You've made some mistakes I feel. 我感觉到您犯了一些错误。

@Embedded is a way to represent an object/component made from selected fields in table. @Embedded是一种表示由表中选定字段构成的对象/组件的方法。 You can use it to represent composite keys but you need to also use @EmbeddedId. 您可以使用它来表示组合键,但是还需要使用@EmbeddedId。

Looking at what you are trying to achieve I feel you can get there with a much simpler mapping. 看看您要实现的目标,我认为您可以通过更简单的映射来达到目标​​。 (a few parts omitted for brevity) (为简洁起见,省略了一些部分)

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

}

If Player is a join/link table you can use an @Embedded static class to represent the composite key, see the book Java Persistence with JPA for further information on this. 如果Player是联接/链接表,则可以使用@Embedded静态类表示组合键,有关此内容的更多信息,请参见《 Java Persistence with JPA》。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM