yegor256
yegor256

Reputation: 105193

How to define many-to-many to itself in JPA?

I'm trying to define this SQL schema in JPA:

TABLE event (id INT)
TABLE chain (predecessor INT, successor INT)

In other words, every event has a number of successors, which are events themselves. I'm trying to do it this way in JPA:

@Entity
public class Event {
  @Id Integer id;
  @ManyToMany(cascade = CascadeType.PERSIST)
  @JoinTable(
    name = "chain",
    joinColumns = @JoinColumn(name = "successor"),
    inverseJoinColumns = @JoinColumn(name = "predecessor")
  )
  private Collection<Event> predecessors;
}

@Entity
public class Chain {
  @Id Integer id;
  @ManyToOne(cascade = CascadeType.PERSIST)
  @JoinColumn(name = "predecessor")
  private Event predecessor;
  @ManyToOne(cascade = CascadeType.PERSIST)
  @JoinColumn(name = "successor")
  private Event successor;
}

Is it correct?

Upvotes: 2

Views: 2206

Answers (2)

Affe
Affe

Reputation: 47994

Normally one would not both define a ManyToMany with a JoinTable and then also separately define the join table as its own Entity. Join tables aren't Entities normally, they're just join tables and the provider manages them under the hood. You're creating a lot of headaches for yourself as far as properly maintaining in memory state of the application when you change one or the other. (Which is necessary if, for example, you want to use L2 caching.)

So, either one works fine, combined, they are sort of oddsauce. Usually if you defined Chain as an entity, you would just have a list of Chain on the Event. Not also redefine it as a JoinTable on Event. Does that make sense?

(and as it is currently strictly defined, it will break if you try to make changes through the collection on Event unless that ID is a database generated sequence.)

Edit: something like this -

@Entity
public class Event {
  @Id Integer id;

  @OneToMany(cascade = CascadeType.PERSIST, mappedBy="successor")
  private Collection<Chain> predecessorChains;
}

What you wrote originally can be made to work as long as you realize that the Collection<Event> predecessors is inherently read only and will get fubared if you try to L2 cache it. The fact that you put a CascadeType on it makes one thing that you wanted to be able to add and remove Events to/from that, which will explode when hibernate tries to execute illegal SQL.

Upvotes: 1

axtavt
axtavt

Reputation: 242786

If you use @ManyToMany, you don't need Chain entity (otherwise, if you need Chain entity, for example, to store additional data associated with the relathionship, you need to declare two one-to-many relationships between Event and Chain).

Upvotes: 1

Related Questions