Java >> Java Tutorial >  >> Java

jOOQ-Tipps:Implementieren einer schreibgeschützten 1:n-Beziehung

Dieser Blogbeitrag beschreibt, wie wir eine Eins-zu-Viele-Beziehung implementieren können, wenn wir Daten aus der Datenbank mit jOOQ abfragen. Nachdem wir diesen Blogbeitrag fertiggestellt haben, werden wir:

  • Kann die erforderlichen Abhängigkeiten mit Maven und Gradle erhalten.
  • Kann die erforderlichen Informationen aus der Datenbank abrufen, indem nur eine verwendet wird Datenbankabfrage.
  • Verstehen Sie, wie wir eine schreibgeschützte 1:n-Beziehung mit jOOQ implementieren können.

Beginnen wir mit einem kurzen Blick auf die Anforderungen unseres Beispiels.

Die Anforderungen unseres Beispiels

Die Datenbank unserer Beispielanwendung hat zwei Tabellen:

Zuerst , der students Die Tabelle enthält die Informationen der in der Datenbank gespeicherten Schüler. Diese Tabelle hat zwei Spalten:

  • Der id Spalte enthält die eindeutige ID des Schülers.
  • Der name Spalte enthält den vollständigen Namen des Schülers.

Zweite , der books Die Tabelle enthält die Informationen zu den Büchern, die den Schülern gehören und aus students gefunden wurden Tisch. Diese Tabelle hat drei Spalten:

  • Der id Spalte enthält die eindeutige ID des Buchs.
  • Der name Spalte enthält den Namen des Buches.
  • Die student_id Spalte enthält die ID des Schülers, dem das Buch gehört.

Die folgende Abbildung veranschaulicht die Struktur unserer Datenbank:

Während dieses Blogposts werden wir einen StudentRepository schreiben -Klasse, die Suchmethoden bereitstellt, die zum Abfragen von Schülerinformationen aus der Datenbank verwendet werden. Diese Methoden sind:

  • Der List<StudentDTO> findAll() -Methode gibt die Informationen aller gefundenen Schüler aus der Datenbank zurück.
  • Der Optional<StudentDTO> findById(Long id) -Methode gibt einen Optional zurück Objekt, das die Informationen des angegebenen Schülers enthält. Wenn kein Schüler gefunden wird, gibt diese Methode einen leeren Optional zurück Objekt.

Die StudentDTO Klasse enthält die Informationen eines Schülers und ihr Quellcode sieht wie folgt aus:

import java.util.List;

public class StudentDTO {

 private Long id;
 private String name;
 private List<BookDTO> books;

 //Getters and setters are omitted
}

Wie wir sehen können, müssen bei beiden Methoden auch die Bücher zurückgegeben werden, die den zurückgegebenen Schülern gehören. Der BookDTO Klasse enthält die Informationen eines Buches und ihr Quellcode sieht wie folgt aus:

public class BookDTO {

 private Long id;
 private String name;

 //Getters and setters are omitted
}

Bevor wir die erforderlichen Suchmethoden implementieren können, müssen wir die erforderlichen Abhängigkeiten abrufen. Als nächstes werden wir herausfinden, wie wir die erforderlichen Abhängigkeiten mit Maven und Gradle erhalten können.

Erforderliche Abhängigkeiten abrufen

Wir werden die Bibliothek namens SimpleFlatMapper verwenden, um die Abfrageergebnisse in StudentDTO umzuwandeln Objekte. Da wir mehrere Zeilen einem einzigen Objekt zuordnen möchten, müssen wir ResultSet verarbeiten Objekte. Deshalb müssen wir die JDBC-Integration von SimpleFlatMapper verwenden. Mit anderen Worten, wir müssen den sfm-jdbc deklarieren Abhängigkeit in unserem Build-Skript.

Wenn wir Maven verwenden, müssen wir das folgende Snippet zum dependencies hinzufügen Abschnitt unserer POM-Datei:

<dependency>
 <groupId>org.simpleflatmapper</groupId>
 <artifactId>sfm-jdbc</artifactId>
 <version>3.17.4</version>
</dependency>

Wenn wir Gradle verwenden, müssen wir den sfm-jdbc hinzufügen Abhängigkeit zum compile Abhängigkeitskonfiguration. Mit anderen Worten, wir müssen das folgende Snippet zu unserer build.gradle hinzufügen Datei:

dependencies {
 compile(
 'org.simpleflatmapper:sfm-jdbc:3.17.4'
 )
}

Lassen Sie uns weitermachen und herausfinden, wie wir eine schreibgeschützte 1:n-Beziehung mit Spring Framework, jOOQ und SimpleFlatMapper implementieren können.

Implementieren einer schreibgeschützten 1:n-Beziehung mit jOOQ und SimpleFlatMapper

Bevor wir unsere Finder-Methoden implementieren können, müssen wir unsere Repository-Klasse erstellen, indem wir diesen Schritten folgen:

  1. Erstellen Sie eine neue Paket-Privatklasse namens StudentRepository und kommentieren Sie die erstellte Klasse mit dem @Repository Anmerkung.
  2. Fügen Sie einen DSLContext hinzu -Feld in die erstellte Klasse und stellen Sie sicher, dass der Spring-Container den echten DSLContext einfügt Objekt in dieses Feld mithilfe der Konstruktorinjektion.
  3. Fügen Sie einen JdbcMapper<StudentDTO> hinzu Feld zur erstellten Klasse. Wir verwenden dieses Feld, wenn wir unsere Abfrageergebnisse in StudentDTO umwandeln Objekte.
  4. Stellen Sie sicher, dass der Konstruktor von StudentRepository Klasse erstellt einen neuen JdbcMapper<StudentDTO> Objekt mit dem JdbcMapperFactory Klasse. Wenn wir einen neuen JdbcMapper<StudentDTO> erstellen -Objekt müssen wir die Schlüssel konfigurieren, die verwendet werden, um den eindeutigen StudentDTO zu identifizieren und BookDTO Objekte. Da die Primärschlüsselspalten des students und books Tabellen werden aus dem ResultSet gefunden unter Verwendung der Aliase:id und books_id , müssen wir diese beiden Aliase als Schlüssel markieren.
  5. Speichern Sie den erstellten JdbcMapper<StudentDTO> Objekt im jdbcMapper Feld.

Nachdem wir unsere Repository-Klasse erstellt haben, sieht ihr Quellcode wie folgt aus:

import org.jooq.DSLContext;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }
}

Wir sind jetzt bereit, unsere Finder-Methoden zu schreiben. Beginnen wir mit der Implementierung von findAll() Methode.

Implementieren der Methode findAll()

Wenn wir alle aus der Datenbank gefundenen Schüler zurückgeben möchten, müssen wir unsere Suchmethode wie folgt implementieren:

Zuerst , müssen wir einen findAll() hinzufügen -Methode zu unserer Repository-Klasse hinzufügen und sicherstellen, dass unsere Datenbankabfrage innerhalb einer schreibgeschützten Transaktion ausgeführt wird. Diese Methode akzeptiert keine Methodenparameter und gibt einen List<StudentDTO> zurück Objekt.

Nachdem wir den findAll() hinzugefügt haben -Methode zu unserer Repository-Klasse, dem Quellcode von StudentRepository Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }

 @Transactional(readOnly = true)
 public List<StudentDTO> findAll() {

 }
}

Zweite , müssen wir die Datenbankabfrage implementieren, die alle gefundenen Schüler aus der Datenbank zurückgibt. Wir können diese Datenbankabfrage mit jOOQ implementieren, indem wir diesen Schritten folgen:

  1. Wählen Sie id und name Spalten aus students Tisch. Denn die Namen dieser Spalten sind gleich den Feldnamen des StudentDTO Klasse müssen wir keine Aliase verwenden.
  2. Wählen Sie id und name Spalten aus books Tisch. Wenn wir Spalten auswählen, deren Werte auf das untergeordnete Objekt der Eins-zu-Viele-Beziehung gesetzt sind, müssen wir Alies auf die ausgewählten Spalten setzen, sonst kann der SimpleFlatMapper die untergeordneten Objekte nicht füllen. Wir können diese Aliase mithilfe dieser Regel erstellen:[der Name des Sammlungsfelds]_[der Feldname der untergeordneten Klasse] . Mit anderen Worten, weil der Name der List<BookDTO> Feld ist books und die BookDTO Klasse hat den id und name Felder müssen wir diese Aliase verwenden:books_id und books_name .
  3. Fügen Sie einen FROM hinzu -Klausel zur erstellten Datenbankabfrage hinzufügen und sicherstellen, dass die Abfrageergebnisse aus students ausgewählt werden Tabelle.
  4. Stellen Sie sicher, dass unsere Datenbankabfrage die Bücher der zurückgegebenen Schüler zurückgibt. Da wir möchten, dass unsere Abfrage Schüler zurückgibt, die keine Bücher haben, müssen wir eine Linksverknüpfung verwenden.
  5. Sortieren Sie die Abfrageergebnisse in aufsteigender Reihenfolge mit dem id Spalte des students Tisch. Dies ist ein entscheidender Schritt, da er sicherstellt, dass SimpleFlatMapper kein Duplikat von StudentDTO erstellt Objekte, wenn es unsere Abfrageergebnisse in eine Liste von StudentDTO umwandelt Objekte.
  6. Speichern Sie den ResultQuery Objekt, das unsere Datenbankabfrage in einer lokalen Variablen enthält.

Nachdem wir unsere Datenbankabfrage mit jOOQ implementiert haben, wird der Quellcode der StudentRepository Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.jooq.ResultQuery;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static net.petrikainulainen.jooqtips.db.Tables.BOOKS;
import static net.petrikainulainen.jooqtips.db.Tables.STUDENTS;

@Repository
class StudentRepository {
 
 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }
 
 @Transactional(readOnly = true)
 public List<StudentDTO> findAll() {
 ResultQuery query = jooq.select(STUDENTS.ID,
 STUDENTS.NAME,
 BOOKS.ID.as("books_id"),
 BOOKS.NAME.as("books_name")
 )
 .from(STUDENTS)
 .leftJoin(BOOKS).on(BOOKS.STUDENT_ID.eq(STUDENTS.ID))
 .orderBy(STUDENTS.ID.asc());
 }
}

Dritter , müssen wir den ResultQuery transformieren Objekt in eine Liste von StudentDTO Objekte. Wir können dies tun, indem wir diesen Schritten folgen:

  1. Fügen Sie einen private hinzu Methode namens transformQueryIntoList() zu unserer Repository-Klasse. Diese Methode nimmt einen ResultQuery entgegen Objekt als Methodenparameter und gibt einen List<Student> zurück Objekt.
  2. Implementieren Sie transformQueryIntoList() Methode. Unsere Implementierung wandelt unser Abfrageobjekt in eine Liste von StudentDTO um Objekte und gibt die erstellte Liste zurück. Auch, wenn unsere Implementierung einen SQLException auslöst , diese Methode hüllt es in eine ungeprüfte Ausnahme namens DataQueryException und wirft den erstellten DataQueryException .
  3. Stellen Sie sicher, dass findAll() Methode ruft den transformQueryIntoList() auf -Methode und gibt eine Liste von StudentDTO zurück Objekte.

Nachdem wir unsere Abfrageergebnisse in eine Liste von StudentDTO umgewandelt haben Objekten sieht der Quellcode unserer Repository-Klasse wie folgt aus:

import org.jooq.DSLContext;
import org.jooq.ResultQuery;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;

import static net.petrikainulainen.jooqtips.db.Tables.BOOKS;
import static net.petrikainulainen.jooqtips.db.Tables.STUDENTS;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }

 @Transactional(readOnly = true)
 public List<StudentDTO> findAll() {
 ResultQuery query = jooq.select(STUDENTS.ID,
 STUDENTS.NAME,
 BOOKS.ID.as("books_id"),
 BOOKS.NAME.as("books_name")
 )
 .from(STUDENTS)
 .leftJoin(BOOKS).on(BOOKS.STUDENT_ID.eq(STUDENTS.ID))
 .orderBy(STUDENTS.ID.asc())
 .fetchResultSet();

 return transformQueryIntoList(query);
 }

 private List<StudentDTO> transformQueryIntoList(ResultQuery query) {
 try (ResultSet rs = query.fetchResultSet()) {
 return jdbcMapper.stream(rs).collect(Collectors.toList());
 } catch (SQLException ex) {
 throw new DataQueryException(
 "Cannot transform query result into a list because of an error",
 ex
 );
 }
 }
}

Der Quellcode von DataQueryException Klasse sieht wie folgt aus:

class DataQueryException extends RuntimeException {

 DataQueryException(String messageTemplate, Object... params) {
 super(String.format(messageTemplate, params));
 }

 DataQueryException(String message, Throwable cause) {
 super(message, cause);
 }
}

Wir haben jetzt eine Repository-Methode implementiert, die die Informationen aller gefundenen Schüler aus der Datenbank zurückgibt. Als nächstes werden wir herausfinden, wie wir eine Repository-Methode implementieren können, die die Informationen des angegebenen Schülers zurückgibt.

Implementierung der Methode findById()

Wenn wir die Informationen des angegebenen Schülers zurückgeben möchten, müssen wir unsere Suchmethode wie folgt implementieren:

Zuerst , müssen wir einen findById() hinzufügen -Methode zu unserer Repository-Klasse hinzufügen und sicherstellen, dass unsere Datenbankabfrage innerhalb einer schreibgeschützten Transaktion ausgeführt wird. Diese Methode nimmt die ID des angeforderten Schülers (ein Long Objekt) als Methodenparameter und gibt einen Optional<StudentDTO> zurück Objekt.

Nachdem wir den findById() hinzugefügt haben -Methode zu unserer Repository-Klasse, dem relevanten Teil von StudentRepository Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }
 
 @Transactional(readOnly = true)
 public Optional<StudentDTO> findById(Long id) {
 
 }
}

Zweite , müssen wir die Datenbankabfrage implementieren, die die Informationen des angegebenen Schülers zurückgibt. Wir können diese Datenbankabfrage mit jOOQ implementieren, indem wir die folgenden Änderungen an der Datenbankabfrage vornehmen, die die Informationen aller Schüler zurückgibt:

  1. Stellen Sie sicher, dass unsere Datenbankabfrage die Informationen des Schülers zurückgibt, dessen ID gleich der ID ist, die als Methodenparameter angegeben ist.
  2. Entfernen Sie ORDER BY Klausel. Obwohl unsere Abfrageergebnisse mehrere Zeilen enthalten, benötigen wir den ORDER BY nicht -Klausel, da alle zurückgegebenen Zeilen dieselbe Schüler-ID und denselben vollständigen Namen enthalten.

Nachdem wir unsere Datenbankabfrage mit jOOQ implementiert haben, wird der relevante Teil der StudentDTO Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.jooq.ResultQuery;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

import static net.petrikainulainen.jooqtips.db.Tables.BOOKS;
import static net.petrikainulainen.jooqtips.db.Tables.STUDENTS;

@Repository
class StudentRepository {
 
 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }
 
 @Transactional(readOnly = true)
 public Optional<StudentDTO> findById(Long id) {
 ResultQuery query = jooq.select(STUDENTS.ID,
 STUDENTS.NAME,
 BOOKS.ID.as("books_id"),
 BOOKS.NAME.as("books_name")
 )
 .from(STUDENTS)
 .leftJoin(BOOKS).on(BOOKS.STUDENT_ID.eq(STUDENTS.ID))
 .where(STUDENTS.ID.eq(id));
 }
}

Dritter , müssen wir eine Methode namens transformQueryIntoObject() hinzufügen an die StudentRepository Klasse. Diese Methode transformiert einen ResultQuery Objekt in einen Optional<StudentDTO> Objekt und gibt das erstellte Objekt zurück. Nachdem wir diese Methode zu unserer Repository-Klasse hinzugefügt haben, müssen wir diese Methode folgendermaßen implementieren:

  1. Holen Sie sich einen ResultSet Objekt, das unsere Abfrageergebnisse enthält.
  2. Transformiere die ResultSet Objekt, das als Methodenparameter in einen Iterator<StudentDTO> gegeben wird Objekt.
  3. Wenn der erstellte Iterator leer ist, geben Sie einen leeren Optional zurück Objekt.
  4. Wenn der erstellte Iterator ein Objekt enthält, geben Sie einen Optional zurück Objekt, das den gefundenen StudentDTO enthält Objekt.
  5. Wenn der erstellte Iterator mehrere Objekte enthält, werfen Sie einen neuen DataQueryException .
  6. Wenn unsere Implementierung einen SQLException auslöst , müssen wir die ausgelöste Ausnahme in eine ungeprüfte Ausnahme namens DataQueryException einschließen und wirf den erstellten DataQueryException .

Nachdem wir diese Methode implementiert haben, wird der relevante Teil der StudentRepository Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.jooq.ResultQuery;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Optional;

import static net.petrikainulainen.jooqtips.db.Tables.BOOKS;
import static net.petrikainulainen.jooqtips.db.Tables.STUDENTS;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }

 @Transactional(readOnly = true)
 public Optional<StudentDTO> findById(Long id) {
 ResultQuery query = jooq.select(STUDENTS.ID,
 STUDENTS.NAME,
 BOOKS.ID.as("books_id"),
 BOOKS.NAME.as("books_name")
 )
 .from(STUDENTS)
 .leftJoin(BOOKS).on(BOOKS.STUDENT_ID.eq(STUDENTS.ID))
 .where(STUDENTS.ID.eq(id))
 .fetchResultSet();
 }

 private Optional<StudentDTO> transformQueryIntoObject(ResultQuery query) {
 try (ResultSet rs = query.fetchResultSet()) {
 Iterator<StudentDTO> students = jdbcMapper.iterator(rs);
 if (!students.hasNext()) {
 return Optional.empty();
 }

 StudentDTO found = students.next();
 if (students.hasNext()) {
 throw new DataQueryException("Multiple students were found");
 }

 return Optional.of(found);
 }
 catch (SQLException ex) {
 throw new DataQueryException(
 "Cannot transform query result into object because of an error",
 ex
 );
 }
 }
}

Vierter , müssen wir sicherstellen, dass die findById() -Methode transformiert den ResultQuery Objekt in einen Optional<StudentDTO> Objekt und gibt das erstellte Objekt zurück.

Nachdem wir dies getan haben, wird der relevante Teil der StudentRepository Klasse sieht wie folgt aus:

import org.jooq.DSLContext;
import org.jooq.ResultQuery;
import org.simpleflatmapper.jdbc.JdbcMapper;
import org.simpleflatmapper.jdbc.JdbcMapperFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Optional;

import static net.petrikainulainen.jooqtips.db.Tables.BOOKS;
import static net.petrikainulainen.jooqtips.db.Tables.STUDENTS;

@Repository
class StudentRepository {

 private final JdbcMapper<StudentDTO> jdbcMapper;
 private final DSLContext jooq;

 @Autowired
 StudentRepository(DSLContext jooq) {
 this.jdbcMapper = JdbcMapperFactory
 .newInstance()
 .addKeys("id", "books_id")
 .newMapper(StudentDTO.class);

 this.jooq = jooq;
 }

 @Transactional(readOnly = true)
 public Optional<StudentDTO> findById(Long id) {
 ResultQuery query = jooq.select(STUDENTS.ID,
 STUDENTS.NAME,
 BOOKS.ID.as("books_id"),
 BOOKS.NAME.as("books_name")
 )
 .from(STUDENTS)
 .leftJoin(BOOKS).on(BOOKS.STUDENT_ID.eq(STUDENTS.ID))
 .where(STUDENTS.ID.eq(id))
 .fetchResultSet();

 return transformQueryIntoObject(query);
 }

 private Optional<StudentDTO> transformQueryIntoObject(ResultQuery query) {
 try (ResultSet rs = query.fetchResultSet()) {
 Iterator<StudentDTO> students = jdbcMapper.iterator(rs);
 if (!students.hasNext()) {
 return Optional.empty();
 }

 StudentDTO found = students.next();
 if (students.hasNext()) {
 throw new DataQueryException("Multiple students were found");
 }

 return Optional.of(found);
 }
 catch (SQLException ex) {
 throw new DataQueryException(
 "Cannot transform query result into object because of an error",
 ex
 );
 }
 }
}

Wir haben jetzt zwei Finder-Methoden implementiert, die zeigen, wie wir eine schreibgeschützte Eins-zu-Viele-Beziehung mit jOOQ und SimpleFlatMapper implementieren können. Fassen wir zusammen, was wir aus diesem Blogbeitrag gelernt haben.

Zusammenfassung

Dieser Blogbeitrag hat uns fünf Dinge beigebracht:

  • Da wir mehrere Zeilen auf ein Objekt abbilden wollen, müssen wir die JDBC-Integration des SimpleFlatMapper verwenden
  • Wir müssen den sfm-jdbc deklarieren Abhängigkeit in unserem Build-Skript.
  • Wir müssen sicherstellen, dass sich der Primärschlüssel des "Root"-Objekts nicht ändert, bis alle Zeilen, die die Informationen des gleichen "Root"-Objekts enthalten, vom JdbcMapper verarbeitet wurden Objekt.
  • Wir können einen ResultSet transformieren Objekt in das zurückgegebene Objekt mithilfe von JdbcMapper Klasse.
  • Wenn wir den JdbcMapper erstellen Objekt mit dem JdbcMapperFactory Klasse müssen wir die Primärschlüsselspalten der Wurzel- und Kindtabellen als Schlüssel markieren.

Java-Tag