JPA 2: использование нескольких столбцов во внешних ключах - PullRequest
14 голосов
/ 16 января 2011

Я использую 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. Это не очень красиво, потому что мне понадобится игровой персонаж только один раз. Чтобы пометить столбцы fk в символе из плитки и группы с помощью inserttable = false, updateable = false позволит генерацию sql, но я не могу изменить / установить эти значения.

Конечно, я мог бы ввести искусственный ПК в группу и плитку, но мне нужно больше соединений.

JPA ограничен только тем, что мне нужно разрешить колонку gameid более одного раза с другими именами? Или мой дизайн не оптимален?

Ждем ваших отзывов и заранее спасибо. Привет Markus

PS (редактировать): В данный момент я позволяю генерации shema генерировать hibernate при запуске, пока моя модель не будет завершена. Но вот сгенерированная схема (немного упрощенная и вырезанная из неважных полей):

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

Когда я делаю оба параметра вставляемыми = 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 ]

8 голосов
/ 28 июня 2016

Вам нужно сделать это:

@ManyToOne
@JoinColumns({
    @JoinColumn(name="gameid", referencedColumnName = "gameid", insertable = false, updatable = false ),
    @JoinColumn(name="groupTag", referencedColumnName = "grouptag", insertable = false, updatable = false)
})
private Group group;
3 голосов
/ 16 января 2011

Вы уверены, что не можете использовать insertable = false, updateable = false для этих @JoinColumn с?

Насколько я понимаю, вы можете инициализировать gameid один раз, установив свойство game, и после этого вам не нужно его менять, поскольку Tile s и Group s принадлежат одному и тому же Game.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...