Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA 3-way join annotation

Tags:

java

orm

jpa

jpql

There are three tables modeled as three entities:

@Entity
@Table(name="event")
public class Event {
  public Long datetime;
  public String name;
  public Long processId;
}

@Entity
@Table(name="process")
public class Process {
  public Long Id;
  public Long sequence;
  public Name name;
}

@Entity
@Table(name="operation")
public class Operation {
  public Long Id;
  public Long datetime;
  public Long sequence;
}

Any unique single record of process-operation-sequence is obtained by the SQL that has a 3-way join constraint:

SELECT *
FROM event e, process p, operation q 
WHERE e.processId = p.id
  AND e.datetime = q.datetime
  AND p.sequence = q.sequence

To implement that in JPA, I have to make a list of operations, which would be explicitly narrowed down to a single record thro the JQPL equality p.sequence = q.sequence

@Entity
@Table(name="event")
public class Event {
  public Long datetime;
  public String name;
  public Long processId;
  @OneToOne
  @JoinColumn(
    name = "processId", referencedColumnName="id",
    insertable=false, updatable=false)
  private Process process;

  @OneToMany
  @JoinColumn(
    name = "datetime", referencedColumnName="datetime",
    insertable=false, updatable=false)
  private List<Operation> operations;
}

Where the JPQL specifies the transitive 3rd join constraint:

SELECT e FROM Event e
INNER JOIN FETCH e.process p
INNER JOIN FETCH e.operations q
WHERE p.sequence = q.sequence

However, I want all three constraints to be modeled inside the entity POJO. Shouldn't there be way to use JPA annotations alone to three-way join? As the following entity pseudo-code illustrates:

@Entity
@Table(name="event")
public class Event {
  public Long datetime;
  public String name;
  public Long processId;
  @OneToOne
  @JoinColumn(
    name = "processId", referencedColumnName="id",
    insertable=false, updatable=false)
  private Process process;

  @OneToOne
  @JoinColumn(
    name = "datetime", referencedColumnName="datetime",
    insertable=false, updatable=false)
  @JoinColumn(
    name = "process.sequence", referencedColumnName="sequence",
    insertable=false, updatable=false)
  private Operation operations;
}

So that it would not be necessary to specify transitive-join constraint in the JPQL

SELECT e FROM Event e
INNER JOIN FETCH e.process p
INNER JOIN FETCH e.operations q

How do I model a transitive join using JPA annotations?

like image 640
Blessed Geek Avatar asked Oct 02 '12 20:10

Blessed Geek


People also ask

What is the use of@ JoinColumn annotation?

Annotation Type JoinColumn. Specifies a column for joining an entity association or element collection. If the JoinColumn annotation itself is defaulted, a single join column is assumed and the default values apply. (Optional) The SQL fragment that is used when generating the DDL for the column.

What is mappedBy in@ OneToMany?

The mappedBy attribute of the @OneToMany annotation references the post property in the child PostComment entity, and, this way, Hibernate knows that the bidirectional association is controlled by the @ManyToOne side, which is in charge of managing the Foreign Key column value this table relationship is based on.

What is join in JPA?

First of all, JPA only creates an implicit inner join when we specify a path expression. For example, when we want to select only the Employees that have a Department, and we don't use a path expression like e. department, we should use the JOIN keyword in our query.

What is the use of mappedBy in spring boot?

mappedBy attribute indicates that which entity owns the relationship (in this example, Student) and what reference is used for non-owning entity within owner entity (in this example, branch is the reference name used in Student entity to map Branch entity).


1 Answers

You seem to be trying to model a query, instead of your data. You should model your data correctly, then write your query.

You seem to have

Event

  • process
  • ManyToOne (processId)

Process

  • events - OneToMany
  • operations - OneToMany

Operation

  • process - ManyToOne (sequence) (this one is a little odd, as sequence is not the Id, this is outside of the JPA spec, but some JPA provider may support it)

To query all operations for an event, you could use,

Select o from Operation o join o.process p join p.events e where e.datetime = o.datetime

To get all the object back use,

Select o, p, e from Operation o join o.process p join p.events e where e.datetime = o.datetime

If you really need to model the query as a relationship, this is outside of the JPA spec, but some JPA providers may support it. In EclipseLink you can use a DescriptorCustomizer to configure any relationship to use any expression criteria, or you own SQL.

like image 145
James Avatar answered Sep 22 '22 06:09

James