我目前正在构建一款瓷砖游戏。在我原来的“游戏”中,我的棋盘有一个
Tile tiles[][];
现在我想用 JPA 来持久化这个,据我所知,你不能持久化多维数组。
所以我想改变它。我可以为要获取的位置创建一个点类
map<Point,Tile>
我相信我会得到类似的东西:
@Entity
public class Board{
@Id
private long id;
...
@OneToMany(mappedBy="board")
@MapKeyJoinColumn(name="POINT_ID")
private Map<Point, Tile> tiles;
...
}
@Entity
public class Tile{
@Id
private long id;
...
@ManyToOne
private Board board;
...
}
@Entity
public class Point{
@Id
private long id;
...
@Column(name = "ROW")
private int row;
@Column(name = "COL")
private int col;
...
}
或者我可以使用
map<Integer, Map<Integer, Tile>>
(不知道如何在 JPA 中执行此操作)
我走在正确的轨道上吗?最好的方法是什么(性能等......)还是我想太多了?
谢谢大家。
最佳答案
Hibernate 类型项目
hibernate-types项目允许您为 JPA 和 Hibernate 实体属性保留多维数组。
因此,如果您需要保留 Tile[][]
数组,您可以轻松实现,而无需将其转换为 Map
。
现在,我有一个非常相似的示例,其中包含用于飞机座位预订系统的二维数组。
数据库表
因此,假设您有以下plane
数据库表:
CREATE TABLE plane (
id INT8 NOT NULL,
name VARCHAR(255),
seat_grid seat_status[][],
PRIMARY KEY (id)
)
其中 seat_status
是 PostgreSQL 枚举:
CREATE TYPE seat_status
AS ENUM (
'UNRESERVED',
'RESERVED',
'BLOCKED'
);
JPA 实体
您可以按如下方式映射plane
数据库表:
@Entity(name = "Plane")
@Table(name = "plane")
@TypeDef(
name = "seat_status_array",
typeClass = EnumArrayType.class
)
public static class Plane {
@Id
private Long id;
private String name;
@Type(
type = "seat_status_array",
parameters = @org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "seat_status"
)
)
@Column(
name = "seat_grid",
columnDefinition = "seat_status[][]"
)
private SeatStatus[][] seatGrid;
//Getters and setters omitted for brevity
public SeatStatus getSeatStatus(int row, char letter) {
return seatGrid[row - 1][letter - 65];
}
}
因此,您需要声明要使用的适当的 Hibernate 类型。对于枚举,您需要使用EnumArrayType
:
@TypeDef(
name = "seat_status_array",
typeClass = EnumArrayType.class
)
@Type
注解允许您将参数传递给 Hibernate Type,就像 SQL 数组类一样:
@Type(
type = "seat_status_array",
parameters = @org.hibernate.annotations.Parameter(
name = "sql_array_type",
value = "seat_status"
)
)
测试时间
现在,当您保留以下 Post
实体时:
entityManager.persist(
new Plane()
.setId(1L)
.setName("ATR-42")
.setSeatGrid(
new SeatStatus[][] {
{
SeatStatus.BLOCKED, SeatStatus.BLOCKED,
SeatStatus.BLOCKED, SeatStatus.BLOCKED
},
{
SeatStatus.UNRESERVED, SeatStatus.UNRESERVED,
SeatStatus.RESERVED, SeatStatus.UNRESERVED
},
{
SeatStatus.RESERVED, SeatStatus.RESERVED,
SeatStatus.RESERVED, SeatStatus.RESERVED
}
}
)
);
Hibernate 将发出正确的 SQL INSERT 语句:
INSERT INTO plane (
name,
seat_grid,
id
)
VALUES (
'ATR-42',
{
{"BLOCKED", "BLOCKED", "BLOCKED", "BLOCKED"},
{"UNRESERVED", "UNRESERVED", "RESERVED", "UNRESERVED"},
{"RESERVED", "RESERVED", "RESERVED", "RESERVED"}
},
1
)
并且,在获取实体时,一切都按预期工作:
Plane plane = entityManager.find(Plane.class, 1L);
assertEquals("ATR-42", plane.getName());
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'A'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'B'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'C'));
assertEquals(SeatStatus.BLOCKED, plane.getSeatStatus(1, 'D'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'A'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'B'));
assertEquals(SeatStatus.RESERVED, plane.getSeatStatus(2, 'C'));
assertEquals(SeatStatus.UNRESERVED, plane.getSeatStatus(2, 'D'));
有关此主题的更多详细信息,请查看 this article .
关于java - 多维数组映射<Integer, Map<Integer,Entity>> 或map<Entity1,Entity2>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19987563/