简体   繁体   中英

Multidimensional array to map<Integer, Map<Integer,Entity>> or map<Entity1,Entity2>

I'm currently building an tile game. In my original "game" my board has an

Tile tiles[][]; 

Now I want to persist this with JPA and for so far as I know you can't persist multidimensional array's.

So I was looking in to change it. I can create a point class for the location to get

map<Point,Tile>

I believe I would get something like:

@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;

  ...
}

or I could use

map<Integer, Map<Integer, Tile>>

(No idea how to do this in JPA)

Am I on the right track and what would be the best way (performance, etc ...) or am I overthinking this?

Thx all.

Hibernate Types project

The hibernate-types project allows you to persist multidimensional arrays for your JPA and Hibernate entity attributes.

So, if you need to persist the Tile[][] array, you can easily to that without having to transform that to a Map .

Now, I have a very similar example with a two-dimensional array for a plane seat reservation system.

Database table

So, assuming you have the following plane database table:

CREATE TABLE plane (
    id INT8 NOT NULL,
    name VARCHAR(255),
    seat_grid seat_status[][],
    PRIMARY KEY (id)
)

Where the seat_status is a PostgreSQL enum:

CREATE TYPE seat_status
AS ENUM (
    'UNRESERVED',
    'RESERVED',
    'BLOCKED'
);

JPA entity

You can map the plane database table as follows:

@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];
    }
}

So, you need to declare the appropriate Hibernate Type to use. For enums, you need to use the EnumArrayType :

@TypeDef(
    name = "seat_status_array",
    typeClass = EnumArrayType.class
)

The @Type annotation allows you to pass parameters to the Hibernate Type, like the SQL array class:

@Type(
    type = "seat_status_array",
    parameters = @org.hibernate.annotations.Parameter(
        name = "sql_array_type",
        value = "seat_status"
    )
)

Testing time

Now, when you persist the following Post entity:

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 will issue the proper SQL INSERT statement:

INSERT INTO plane (
    name,
    seat_grid,
    id
)
VALUES (
    'ATR-42',
    {
        {"BLOCKED", "BLOCKED", "BLOCKED", "BLOCKED"},
        {"UNRESERVED", "UNRESERVED", "RESERVED", "UNRESERVED"},
        {"RESERVED", "RESERVED", "RESERVED", "RESERVED"}
    },
    1
)

And, when fetching the entity, everything works as expected:

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'));

For more details about this topic, check out this article .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM