Problem: Mehrere Datenbankzugriffe bei Join-Tabellen notwendig
JPA ist eine weitverbreitete Schnittstelle für Datenbankzugriffe und objektrelationales Mapping (ORM). Mit Hilfe der Annotationen @ManyToMany und @JoinTable können n:m-Beziehungen zwischen Datenbank-Tabellen komfortabel, schnell und lesbar beschrieben werden. Aufgrund dieser Beschreibung existiert jedoch keine eigene Java-Klasse der Join-Tabelle, was dazu führt, dass zuerst alle Objekte des „linken“ Teils der Join-Tabelle abgerufen werden müssen, bevor über Lazy-Loading der „rechte“-Teil aggregiert werden kann, um letztlich die Information der Join-Tabelle verwenden zu können.
Lösung: JPQL Projection
JPQL kann bei SELECT-Abfragen mit Hilfe des Schlüsselworts NEW und der Angabe eines Konstruktors pro Datensatz ein Objekt erstellen, wodurch es möglich ist, die Join-Tabelle mit EINEM Datenbankzugriff zu erhalten. Das heißt, es wird eine Projektion von Tabellen-Spalten auf ein Objekt durchgeführt.
Beispiel
Ein Projekt hat mehrere Mitarbeitende und jede*r kann in mehreren Projekten arbeiten.
@Entity
public class Project {
@Id @Column(name = "ID")
private long id;
@ManyToMany @JoinTable(name = "PROJECT_EMPLOYEE",
joinColumns = @JoinColumn(name = "PROJECT_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "EMPLOYEE_ID", referencedColumnName = "ID"))
private List<Employee> employees;
}
@Entity
public class Employee {
@Id @Column(name = "ID")
private long id;
@ManyToMany(mappedBy = "employees")
private List<Project> projects;
}
public class JoinTable {
private long projectId, employeeId;
public JoinTable(long projectId, long employeeId) {
this.projectId = projectId; this.employeeId = employeeId;
}
}
// Spring Data
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProjectRepository extends JpaRepository<Project, Long> {
@Query("SELECT NEW com.jambit.toiletpaper.JoinTable(p.id, e.id) FROM Project p " +
"JOIN p.employees e WHERE p.id = ?1")
List<JoinTable> getAllJoinTableById(long id);
}
Weiterführende Aspekte
---
Autor: Matthias Mair / Senior Software Architect / Business Division Automotive Bavaria
Zum Toilet Paper #116: SELECT n:m-Tabellen mit JPQL Projection (pdf)