JPA 2:外键中的多个列用法。

时间:2023-01-08 17:05:27

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

我使用Hibernate作为持久性提供者,并使用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)).

在我的应用程序中,您可以打开一个游戏,在其中创建一组玩家,并在地图上四处走动(tile (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.

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

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

当然,我可以在group和tile中引入一个人工pk,但是我需要更多的连接。

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

JPA是否只是限制了我必须让gameid列不止一次使用其他名称?还是我的设计不是最佳的?

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

PS(编辑):现在我让hibernate在启动时生成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: I already played around with , insertable = false, updatable = false. For example when i change the group JoinColumns to:

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

@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

我有一个错误,混合是不允许的:由:org.hibernate引起的。注释异常:不允许在属性中混合插入和不可插入列: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. :-/

当我使这两个insertable=false时,我不能再设置组标记了。插入后,它的groupTag保持为空,并设置了gameid

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

2 个解决方案

#1


7  

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;

#2


3  

Are you sure you can't use insertable = false, updateable = false for these @JoinColumns?

您确定不能为这些@JoinColumns使用insertable = false、updateable = false吗?

As far as I understand, you can initialize gameid once by setting game property, and after that you don't need to change it since Tiles and Groups belong to the same Game.

据我所知,你可以通过设置game属性来初始化gameid,之后你就不需要修改它了,因为Tiles和group属于同一个游戏。

#1


7  

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;

#2


3  

Are you sure you can't use insertable = false, updateable = false for these @JoinColumns?

您确定不能为这些@JoinColumns使用insertable = false、updateable = false吗?

As far as I understand, you can initialize gameid once by setting game property, and after that you don't need to change it since Tiles and Groups belong to the same Game.

据我所知,你可以通过设置game属性来初始化gameid,之后你就不需要修改它了,因为Tiles和group属于同一个游戏。