简体   繁体   English

JPA 2:外键中的多列使用

[英]JPA 2: multiple column usage in foreign keys

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)).在我的应用程序中,您可以打开一个游戏,在其中创建玩家组并在地图上走动(图块 (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.如您所见,我不得不将 gameid 列重命名为 groupgameid 和 tilegameid。 This is not very pretty because i would need the gameid in character just once.这不是很漂亮,因为我只需要一次游戏 ID。 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.要使用 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.当然我可以在组和瓷砖中引入一个人工 pk,但我需要更多的连接。

Is JPA just limited that i have to allow the gameid column more than once with other names? JPA 是否仅限于我必须多次允许使用其他名称的 gameid 列? 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. PS(编辑):此刻我让shema在启动时通过休眠生成,直到我的模型完成。 But here is the generated shema (bit simplified and cutted out some unimportant fields):但这是生成的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 . PS 2:我已经玩过, insertable = false, updatable = false For example when i change the group JoinColumns to:例如,当我将组 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.AnnotationException:不允许在属性中混合可插入和不可插入的列:net.hq.model.Charactergroup

When i make both insertable=false i am not able to set the group tag anymore.当我同时设置 insertable=false 时,我无法再设置组标签。 It groupTag stays empty after insertion and gameid is set.插入后 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);
}

You need to 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;

EDIT : as mentioned in the comments, @JoinColumn is a repeatable annotation (since Java 8 ) that doesn't need wrapping.编辑:如评论中所述, @JoinColumn是一个不需要包装的可重复注释(自Java 8 起)。 This simplifies the solution to:这将解决方案简化为:

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

Are you sure you can't use insertable = false, updateable = false for these @JoinColumn s?您确定不能对这些@JoinColumn使用insertable = false, updateable = false @JoinColumn 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 Tile s and Group s belong to the same Game .据我了解,您可以通过设置game属性来初始化gameid一次,之后您不需要更改它,因为Tile s 和Group s 属于同一个Game

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

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