簡體   English   中英

兩列一對一休眠(實體類中的兩個相同類型的字段)

[英]Hibernate one to one for two columns (two fields of the same type in an Entity class)

假設我有一個 Noughts and Crosses 游戲(井字游戲):

游戲

id    crosses_player_id    noughts_player_id...

球員

id    alignment    game_id

由於只有 2 個玩家,我認為沒有必要創建一個單獨的表,所以我這樣做了:

@Entity
@Table(name = "games")
public class Game {
    @Id @GeneratedValue
    private int id;

    @OneToOne(mappedBy = "game")
    @JoinColumn(name = "crosses_player_id")
    private Player crossesPlayer;
    @OneToOne(mappedBy = "game")
    @JoinColumn(name = "noughts_player_id")
    private Player noughtsPlayer;

    private List<Move> moves = new ArrayList<>();
    private List<Field> fields = new ArrayList<>();
...
@Entity
@Table(name = "players")
public class Player {
    @ManyToOne
    @JoinColumn(name="user_id", nullable=false)
    private User user;

    private enum Alignment {
        NOUGHTS, CROSSES
    };
    private Alignment alignment;

    @OneToOne(mappedBy = ?)
    private Game game;
...

但是我不確定在Player類的@OneToOne(mappedBy = ?)里面放什么。

我找到的最接近的答案是這個:

https://stackoverflow.com/a/13944195/4759176

class TeamPlay {
    @ManyToOne
    Team homeTeam;

    @ManyToOne
    Team awayTeam;
}

class Team {
    @OneToMany(mappedBy="homeTeam")
    Set<TeamPlay> homeTeamPlays;

    @OneToMany(mappedBy="awayTeam")
    Set<TeamPlay> awayTeamPlays;
}

然而,看起來Team類可以有很多可能的游戲,而在我的情況下,1 個玩家只有 1 個游戲。 玩家基本上是用戶的 id、游戲的 id 和 allighment(noughts 或 crosses),並且在游戲結束后,任何新游戲都不會再引用同一個玩家。 也許我應該這樣做:

球員

@OneToOne(mappedBy = "crossesPlayer")
private Game crossesGame;

@OneToOne(mappedBy = "noughtsPlayer")
private Game noughtsGame;

但是,一個球員只能是零或交叉球員,所以這些領域之一總是為空?

@parsecer ...對我來說,你的問題在於對你的數據模型的誤解; 引用你:

玩家基本上是用戶的 id、游戲的 id 和 allighment(noughts 或 crosses),並且在游戲結束后,任何新游戲都不會再次引用同一玩家

這意味着“游戲”是一個強大的實體,不應該有對玩家的引用(即外鍵)(即表“游戲”不應該包含列:crosses_player_id、noughts_player_id)......這也意味着“玩家“是一個弱實體,只存在於“游戲”的上下文中(所以,這里可以有一個外國專欄來游戲)......

假設所有這些,您的模型和映射都會變得更清晰,例如:

@Entity
@Table(name = "players")
public class Player {
    /**
     * Player's ID.
     */
    @Id
    private int id;

    /**
     * Game to which this Player belongs.
     */
    @ManyToOne(optional = false)
    @JoinColumn(name = "game_id", nullable = false, updatable = false)
    private Game game;

    /**
     * Player's alignment in the game.
     */
    @Enumerated(EnumType.STRING)
    private Alignment alignment;
}

@Entity
@Table(name = "games")
public class Game {
    /**
     * Game's Id.
     */
    @Id
    private int id;

    /**
     * Players in this game.
     */
    @OneToMany(mappedBy = "game", cascade = PERSIST)
    @MapKey(name = "alignment")
    private Map<Alignment, Player> players = new HashMap<>();

    ...

    public List<Player> getPlayers() {
        return Arrays.asList( this.players.values() );
    }

    public Player getCrossesPlayer() {
        return this.players.get(Alignment.CROSSES);
    }

    public Player getNoughtesPlayer() {
        return this.players.get(Alignment.NOUGHTES);
    }
}
 @ManyToOne(optional=false) 
 @JoinColumn(name="game_id")
 private Game game;

Player 上的 Game 中的 OneToOne 已經在這些實體之間創建了您想要的關系。 使用帶有 Joining 的游戲主鍵的 ManyToOne,您將能夠看到玩家正在參與的游戲(從數據的玩家視圖中)。 使用該數據邏輯,最多兩個玩家可以在數據層上參與游戲。 但是,您仍然可以創建一個 Player 並為他分配一個他不玩的游戲。

Player player1ThatDoesentPlay // = new Player(...); 
player1ThatDoesentPlay.setGame(thatGame) // with thatGame could already have the participating players

我建議你創建一個像

Game checkandsetGame(Game game){
if (game.crossesplayer == null | game.noughtsplayer == null && game != null){
return setGame(game);
    }
// else {probably want to throw an error here, that indicates that the player couldn't be assigned to a game}
}

一般來說,我建議你過度考慮你的數據模式,也許做一些像@Carlitos Way 建議的事情

在您的模型中,您希望游戲和玩家之間建立 1-1 的關系。 但是兩個玩家將共享一個游戲,因此單個游戲 ID 可能會從玩家表中多次引用,但單個玩家只能從游戲表中引用一次。

您弄錯的一件事是使用了mappedBy屬性,該屬性將用於關系的非擁有方。 它告訴 JPA '我是從另一個表中的那個外鍵引用的。 請為我取回並在此處參考'。 請注意,您必須維護關系的雙方,即,當您調用game.setPlayer(player) ,您必須確保您也調用player.setGame(game) 另請注意,雖然 @OneToOne 關系可能沒問題,但它不可擴展,您最好避免使用它。

您與玩家之間的關系由他們的對齊方式定義。 事實上,您的玩家實體似乎定義了用戶和游戲之間的關系。

我為您的用例提供的解決方案是使用GamePosition表,該表將允許您強制單個玩家只是單個游戲的一部分。

@Entity
@Table(name = "players")
public class Player {
    @ManyToOne
    @JoinColumn(name="user_id", nullable=false)
    private User user;    
}



@Entity
@Table(name = "game")
public class Game {
    @Id @GeneratedValue
    private int id;
}


@Entity
@Table(name = "game_position")
public class GamePosition {

    @OneToOne
    @JoinColumn(name="player_id", unique=true)
    // Making this column unique will prevent a single player to be part of two games
    private Player player;

    @ManyToOne
    @JoinColumn(name="game_id")
    private Game game;

    @Enumarated
    private Alignement alignement;

}

然后如果你想要雙向關系,你可以使用mappedBy 屬性。 在玩家表中:

  @OneToOne(mappedBy="player")
  private GamePosition gamePosition;

或在游戲桌上:

  @OneToMany(mappedBy="game")
  private List<GamePosition> gamePositions;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM