JPA 2:在外键中使用多列 [英] JPA 2: multiple column usage in foreign keys

查看:92
本文介绍了JPA 2:在外键中使用多列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

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

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

  @Entity 
public class Gameizable实现Serializable {
@Id
@SequenceGenerator(name =gen_gameid,sequenceName =seq_gameid)
@GeneratedValue(generator =gen_gameid)
私人长期gameid;

/ **
*演奏角色。
* /
@OneToMany(mappedBy =game)
private List< Character>字符;
private int round = 0;

@OneToMany(mappedBy =游戏)
私人列表< Tile>瓷砖;

@OneToMany(mappedBy =游戏)
私人列表< Group>组;

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

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

@Id
private int x;

@Id
private int y;

@Id @ManyToOne @JoinColumn(name =gameid)
私人游戏游戏;

@OneToOne(mappedBy =tile)
私人字符;

$ / code>

字符:

 @ManyToOne 
@JoinColumn(name =gameid,referencedColumnName =gameid)
私人游戏游戏;
$ b @ManyToOne
@JoinColumns({
@JoinColumn(name =groupgameid,referencedColumnName =gameid),
@JoinColumn(name =groupTag ,referencedColumnName =grouptag)
})
私人群组;

@OneToOne
@JoinColumns({
@JoinColumn(name =x,referencedColumnName =x),
@JoinColumn(name =y ,referencedColumnName =y),
@JoinColumn(name =tilegameid,referencedColumnName =gameid)
})
私有tile tile;

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



当然,我可以在组和瓦片中引入人造pk,但我需要更多连接。

JPA是否仅限于我必须允许gameid列多次与其他名称?或者我的设计不是最优的?



期待您的反馈,并提前致谢。
问候
Markus



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

$ p $ CREATE TABLE字符

charid bigint NOT NULL,
gameid bigint,
组字符变化(255),
x整数,$ b $整数,
CONSTRAINT hero_pkey PRIMARY KEY(charid),
CONSTRAINT fkd4addb09308bc3b822441a FOREIGN KEY(gameid)
REFERENCES game(gameid)MATCH SIMPLE
ON UPDATE NO ACTION ON ACTION,
CONSTRAINT fkd4addb093091cb6522441a FOREIGN KEY(gameid,x,y)
REFERENCES tile(gameid,x,y)MATCH SIMPLE
ON UPDATE NO ACTION ON 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(gam
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)
} )
私人小组小组;

我得到一个不允许混合的错误:
引起:org.hibernate。 AnnotationException:不允许在属性中混用可插入和不可插入的列:net.hq.model.Charactergroup



当我让两个insertable = false时,我无法设置组标签了。插入并设置gameid后,groupTag会保持空白。 : - /



我给组中添加一个字符的方式:

  //创建游戏
游戏游戏= new Game();
game.addCharacter(max);
em.persist(game);

//组
组英雄组=新组(游戏,HEROES);
heroGroup.addCharacter(max);
em.persist(game);

组合类中的方法:

if(this.characters == null)
this.characters = new ArrayList< Character>();

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


解决方案

您需要这样做:

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


I am using Hibernate as persistence provider and modelling my entities with JPA 2.

Now a question came up and i hope you can help me.

In my application you can open up a Game, create groups of players in it and walk around on the map (tiles (2d)).

First my entity definitions: Game:

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

Tile (a tile will be created from a template and belongs to just one game):

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

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;

As you can see i had to rename the gameid column to groupgameid and tilegameid. This is not very pretty because i would need the gameid in character just once. To mark the fk columns in character from tile and group with insertable=false, updateable=false will allow the sql generation, but i can't change/set this values.

Sure i could introduce an artificial pk in group and tile, but i would need more joins.

Is JPA just limited that i have to allow the gameid column more than once with other names? Or is my design not optimal?

Looking forward to your feedback and thanks in advance. greetings Markus

PS (edit): At Moment i let the shema generate by hibernate at startup till my model is complete. But here is the generated shema (bit simplified and cutted out some unimportant fields):

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: I already played around with , insertable = false, updatable = false. For example when i change the group JoinColumns to:

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

I get an Error that mixing is not allowed: Caused by: org.hibernate.AnnotationException: Mixing insertable and non insertable columns in a property is not allowed: net.hq.model.Charactergroup

When i make both insertable=false i am not able to set the group tag anymore. It groupTag stays empty after insertion and gameid is set. :-/

The way i add a Character to a group:

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

Method in Group Class:

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

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

解决方案

You need do this:

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

这篇关于JPA 2:在外键中使用多列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆