2

Possibly I'm understanding the concept wrong, but here is my problem:

I want to store two types of data in my database:

  1. game positions (uniquely represented by some lengthy string, containing two lists of moves - one for moves possible in this position and one for moves leading to this position)
  2. game moves (represented by a smaller string, linking two positions)

In classes:

@Entity
public class Move {
    @Id
    @GeneratedValue
    private long id;
    private String representation;
    private Position positionBeforeMove;
    private Position positionAfterMove;

    ...
}

@Entity 
public class Position {
    @Id
    private String representation;
    private List<Move> movesLeadingToPosition;
    private List<Move> movesLeadingFromPosition;

    ...
}

I want to store a set of games. In this context, the positions are unique, and the moves may occur multiple times in the database.

My naieve implementation uses two tables:

MOVE
number   id                    (PK)
varchar2 representation
varchar2 positionBeforeMove    (FK)
varchar2 positionAfterMove     (FK)
...

POSITION
varchar2 representation        (PK)
...

This works fine; using EntityManager.merge(position) I can grow my POSITION table as I store more and more games, while keeping the positions unique.

However, the solution is not optimal: I'd much prefer to have a generated id like I have in the MOVE table!

@Entity
public class Position {
    @Id
    @GeneratedValue
    private long id;

    private String representation;
    private List<Move> movesLeadingToPosition;
    private List<Move> movesLeadingFromPosition;

    ...
}

MOVE
number   id                    (PK)
varchar2 representation
number   positionBeforeMove_id (FK)
number   positionAfterMove_id  (FK)
...

POSITION
number id;                     (PK)
varchar2 representation        (Unique)
...

But when I implement this, I end up with duplicate representations, because the EntityManager.merge(...) merges based on the specified Id, not the natural key.

Is there any way I can let java (JPA / Hibernate / ...) merge the positions based on the natural key, while still allowing me to use an ID as the key to the table? Or, would I need to merge the positions manually? (for example: Whenever I want to store a move, would I need to retrieve the positionAfterMove and positionBeforeMove from the database, add the move to movesLeadingToPosition and movesLeadingFromPosition respectively, and then update the positions in the database?)

(context: I'm using Java 1.7, JPA, and a MySQL database)

ljgw
  • 2,751
  • 1
  • 20
  • 39

1 Answers1

1

No, not possible; merge() is done using entity key (the @Id target).

Probably you need to add a @NaturalId or mimic as described in JPA equivalent to Hibernate's @NaturalId and check for duplication insertion using business method

Community
  • 1
  • 1
Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69
  • Thank you for pointing me to `@NaturalId`! Can you confirm that I will have to _'merge positions manually'_? (that seems to be the answer in http://stackoverflow.com/questions/6058875/hibernate-natural-id-duplicate-issue). Thanks in advance! – ljgw Feb 24 '14 at 13:46
  • I think so,but - if you have time - wait for someone else answer; maybe people with different experiences can give us another point of view – Luca Basso Ricci Feb 24 '14 at 13:56