JPA 2:外键中的多列使用

时间:2011-01-16 11:38:09

标签: java hibernate postgresql jpa-2.0

我使用Hibernate作为持久性提供程序,并使用JPA 2为我的实体建模。

现在提出了一个问题,我希望你能帮助我。

在我的应用程序中,您可以打开一个游戏,在其中创建一组玩家并在地图上四处走动(平铺(2d))。

首先是我的实体定义: 游戏:

@Entity
public class Game implements Serializable {
@Id
@SequenceGenerator(name = "gen_gameid", sequenceName = "seq_gameid")
@GeneratedValue(generator="gen_gameid")
private long gameid;

/**
 * Playing Characters.
 */
@OneToMany(mappedBy = "game")
private List<Character> characters;
private int round = 0;

@OneToMany(mappedBy="game")
private List<Tile> tiles;

@OneToMany(mappedBy="game")
private List<Group> group;

平铺(将从模板创建一个平铺并且只属于一个游戏):

@Entity @IdClass(TileId.class)
public class Tile implements Serializable{
    private static final long serialVersionUID = 2039974286110729270L;

    @Id
    private int x;

    @Id
    private int y;

    @Id @ManyToOne @JoinColumn(name="gameid")
    private Game game;

    @OneToOne(mappedBy="tile")
    private Character character;
}

字符:

@ManyToOne
@JoinColumn(name="gameid", referencedColumnName = "gameid")
private Game game;

@ManyToOne
@JoinColumns({
    @JoinColumn(name="groupgameid", referencedColumnName = "gameid"),
    @JoinColumn(name="groupTag", referencedColumnName = "grouptag")
})
private Group group;

    @OneToOne
    @JoinColumns({    
      @JoinColumn(name = "x", referencedColumnName = "x"),
      @JoinColumn(name = "y", referencedColumnName = "y"),
      @JoinColumn(name = "tilegameid", referencedColumnName = "gameid")
    })
    private Tile tile;

正如您所看到的,我必须将gameid列重命名为groupgameid和tilegameid。这不是很漂亮,因为我只需要一次角色游戏。 要使用insertable = false从tile和group中标记字符中的fk列,updateable = false将允许sql生成,但我无法更改/设置此值。

当然,我可以在群组和平铺中引入人工PK,但我需要更多连接。

JPA是否仅限于我必须在其他名称上不止一次地允许gameid列?或者我的设计不是最佳的?

期待您的反馈并提前致谢。 问候 马库斯

PS(编辑): 在Moment,我让shema在启动时通过休眠生成,直到我的模型完成。但这里是生成的shema(比特简化并切除了一些不重要的字段):

CREATE TABLE Character
(
  charid bigint NOT NULL,
  gameid bigint,
  grouptag character varying(255),
  x integer,
  y integer,
  CONSTRAINT hero_pkey PRIMARY KEY (charid),
  CONSTRAINT fkd4addb09308bc3b822441a FOREIGN KEY (gameid)
  REFERENCES game (gameid) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fkd4addb093091cb6522441a FOREIGN KEY (gameid, x, y)
  REFERENCES tile (gameid, x, y) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fkd4addb09c018f3ae22441a FOREIGN KEY (gameid, grouptag)
  REFERENCES gamegroup (gameid, grouptag) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION
) 

CREATE TABLE tile (
  x integer NOT NULL,
  y integer NOT NULL,
  gameid bigint NOT NULL,
  CONSTRAINT tile_pkey PRIMARY KEY (gameid, x, y),
  CONSTRAINT fk27c6ce308bc3b8 FOREIGN KEY (gameid)
  REFERENCES game (gameid) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION)

CREATE TABLE gamegroup
(
  grouptag character varying(255) NOT NULL,
  gameid bigint NOT NULL,
     CONSTRAINT gamegroup_pkey PRIMARY KEY (gameid, grouptag),
  CONSTRAINT fk3c1c51cd308bc3b8 FOREIGN KEY (gameid)
  REFERENCES game (gameid) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION
)

PS 2:我已经玩过, insertable = false, updatable = false了。 例如,当我将组JoinColumns更改为:

@ManyToOne
@JoinColumns({
    @JoinColumn(name="gameid", referencedColumnName = "gameid", insertable = false, updatable = false ),
    @JoinColumn(name="groupTag", referencedColumnName = "grouptag")
})
private Group group;

我收到错误,说不允许混音:     引起:org.hibernate.AnnotationException:不允许在属性中混合可插入和不可插入的列:net.hq.model.Charactergroup

当我同时使insertable = false时,我无法再设置组标签。插入后,groupTag保持为空并设置了gameid。 : - /

我将角色添加到群组的方式:

// Create game
Game game = new Game();
game.addCharacter(max);
em.persist(game);

// Group
Group heroGroup = new Group(game, "HEROES");
heroGroup.addCharacter(max);
em.persist(game);

小组课程中的方法:

public void addCharacter(Character character){
    if(this.characters == null)
        this.characters = new ArrayList<Character>();

    this.characters.add(character);
    character.setGroup(this);
}

2 个答案:

答案 0 :(得分:8)

你需要这样做:

@ManyToOne
@JoinColumns({
    @JoinColumn(name="gameid", referencedColumnName = "gameid", insertable = false, updatable = false ),
    @JoinColumn(name="groupTag", referencedColumnName = "grouptag", insertable = false, updatable = false)
})
private Group group;

答案 1 :(得分:3)

您确定无法将insertable = false, updateable = false用于这些@JoinColumn吗?

据我了解,您可以通过设置gameid属性来初始化game一次,之后您无需更改Tile和{{1} } s属于同一个Group