Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用于保存复杂游戏状态的JPA设计_Java_Jpa_Jakarta Ee_Database Design - Fatal编程技术网

Java 用于保存复杂游戏状态的JPA设计

Java 用于保存复杂游戏状态的JPA设计,java,jpa,jakarta-ee,database-design,Java,Jpa,Jakarta Ee,Database Design,假设我有一个带有地图和单位的游戏,我想使用JPA2.2在服务器上提供一个保存选项。以下是简化的类来表示它: @Entity class GameState { @Id long gameId; Map<Point, Tile> map; Map<Long, Unit> units; // maps from the id to the unit Map<Long, Soldier> soldiers; // map

假设我有一个带有地图和单位的游戏,我想使用JPA2.2在服务器上提供一个保存选项。以下是简化的类来表示它:

@Entity
class GameState {

    @Id
    long gameId;

    Map<Point, Tile> map;

    Map<Long, Unit> units; // maps from the id to the unit
    Map<Long, Soldier> soldiers; // maps from the id to the soldier
}
所以每个瓷砖上都有一个单位,每个单位都有一些士兵

我有几个问题:

  • 因为可以有很多游戏,所以
    单位
    士兵
    平铺
    实体ID
    不是唯一的。每个游戏中可以有一个id为1的士兵。我不确定是否可以/应该使用
    @Embedded
    ,或者是否可以使用由实体id和游戏id组成的复杂id

  • 的适当注释是什么?它是不变的

  • 地图的适当注释是什么?我的想法是

     @OneToMany(cascade = CascadeType.ALL)
     @JoinTable(name = "unit_mapping", 
       joinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "entityId")},
       inverseJoinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "entityId")})
     @MapKey(name = "id")
    
  • 这是我的尝试,但如果有更好的方法,我想知道。以前我只是将整个状态序列化为一个blob,但我希望能够查询状态的更详细信息

    地图的适当注释是什么

    最简单的方法是使用
    @JoinColumn
    而不是
    @JoinTable
    (我相信,如果您计划将
    游戏
    id作为
    单位
    士兵
    的主键的一部分,这是唯一可行的映射):

    点的适当注释是什么?它是不变的

    由于
    没有标识,我建议您将其设置为
    @可嵌入的

    如何使用游戏ID和实体ID生成复杂ID

    首先,如果我是你的话,我真的要挑战我自己,弄清楚能有多少士兵和部队。一个
    long
    是一个真正的huuuge数,正如您将要看到的,使用复合键映射变得相当复杂

    但是,如果您最终决定需要复合密钥,则需要调整映射,使用共享密钥将单向
    @OneToMany
    更改为双向。结果如下:

    public class UnitKey implements Serializable {
    
        private long entityId;
        private long gameId;
    
        //getters, setters, equals, hashCode
    }
    
    @Entity
    @IdClass(UnitKey.class) // in principle, you could use an EmbeddedId instead, but IdClass is a little more convenient with PKs made partly of FKs IMHO
    public class Unit {
    
        @Id
        private long entityId;
    
        @JoinColumn(name = "game_id")
        @MapsId("gameId")
        private Game game;
    }
    
    @Entity
    public class Game {
    
        @OneToMany(mappedBy = "game", cascadeType = ALL)
        @MapKey(name = "entityId")
        private Map<Long, Unit> units;
    
    }
    
    
    public类UnitKey实现可序列化{
    私有长实体ID;
    私有长配子体;
    //getter、setter、equals、hashCode
    }
    @实体
    @IdClass(UnitKey.class)//原则上,您可以使用EmbeddedId,但是IdClass对于部分由FKs IMHO组成的PKs来说更方便一些
    公营课组{
    @身份证
    私有长实体ID;
    @JoinColumn(name=“game\u id”)
    @MapsId(“配子ID”)
    私人游戏;
    }
    @实体
    公开课游戏{
    @OneToMany(mappedBy=“game”,cascadeType=ALL)
    @映射键(name=“entityId”)
    私人地图单位;
    }
    
    请注意,
    Unit
    不是关联的拥有方。这意味着对关联的任何更改都必须通过调整
    Unit.game
    属性来完成。特别是,要将新的
    单位
    添加到
    游戏
    ,仅将
    单位
    添加到
    游戏.单位
    地图是不够的-您还需要手动设置
    单位.Game
    属性以指向所讨论的
    游戏


    注意,我还没有测试上面的映射。虽然原则上它应该可以工作,但我从未尝试过将地图的一面与复合键的另一面结合起来,因此-没有给出任何保证。

    为什么你需要
    游戏
    单元
    中,而不仅仅是
    长游戏ID
    ?好吧,你可以尝试用
    游戏ID
    来映射它,但是,我不能100%肯定JPA在您同时坚持
    游戏
    单元
    时是否能够正确处理插入顺序。你得检查一下。请记住,
    GAME\u ID
    列将映射两次,一次作为
    @JoinColumn
    ,另一次作为
    @ID
    。其中一个映射必须被标记为
    insertable=false,updateable=false
    如果您想尝试这样的映射,我会首先尝试将
    insertable=false,updateable=false
    放在
    @JoinColumn
    上,并手动将游戏id分配给每个
    Unit.gameId
    @Entity
    class Soldier {
    
        @id
        long entityId;
        
        @ManyToOne(fetch = FetchType.LAZY)
        Unit unit;        
    
        int health;
    }
    
    final class Point {
    
        final int x, y;
    }
    
     @OneToMany(cascade = CascadeType.ALL)
     @JoinTable(name = "unit_mapping", 
       joinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "entityId")},
       inverseJoinColumns = {@JoinColumn(name = "unit_id", referencedColumnName = "entityId")})
     @MapKey(name = "id")
    
    @OneToMany(cascadeType = ALL)
    @JoinColumn(name = "game_id")
    @MapKey(name = "entityId")
    private Map<Long, Unit> units; 
    
    @OneToMany(cascadeType = ALL)
    @JoinTable(name = "unit_mapping", 
        joinColumns = @JoinColumn(name = "game_id"),
        inverseJoinColumns = @JoinColumn(name = "unit_id")
    )
    @MapKey(name = "entityId")
    private Map<Long, Unit> units;
    
    public class UnitKey implements Serializable {
    
        private long entityId;
        private long gameId;
    
        //getters, setters, equals, hashCode
    }
    
    @Entity
    @IdClass(UnitKey.class) // in principle, you could use an EmbeddedId instead, but IdClass is a little more convenient with PKs made partly of FKs IMHO
    public class Unit {
    
        @Id
        private long entityId;
    
        @JoinColumn(name = "game_id")
        @MapsId("gameId")
        private Game game;
    }
    
    @Entity
    public class Game {
    
        @OneToMany(mappedBy = "game", cascadeType = ALL)
        @MapKey(name = "entityId")
        private Map<Long, Unit> units;
    
    }