Подтвердить что ты не робот

JPA 2: использование нескольких столбцов во внешних ключах

Я использую 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 символом из фрагмента и группы с insertable = false, 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);
}
4b9b3361

Ответ 1

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

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

Ответ 2

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

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