[JAVA] Erste Schritte mit Doma-Using Joins mit der Criteira-API

Einführung

Doma Beschreibt die Verwendung von Joins mit der 2.43.0 Criteria API.

Die Criteira-API von Doma unterstützt zwei Muster: "Einfach beitreten" und "Verbinden und verwandte Entitäten abrufen". Letzteres ähnelt in Bezug auf die Auswirkungen dem Join-Abruf von JPA.

Eine Übersicht über Doma und die Kriterien-API finden Sie in den anderen Artikeln unter Einführung in Doma.

In diesem Artikel verwendeter Beispielcode

Hier ist ein vereinfachter Code. Im vollständigen Projekt finden Sie den vollständigen Beispielcode.

Die Datenbank verfügt über eine Abteilungstabelle, die Abteilungen darstellt, und eine Mitarbeitertabelle, die Mitarbeiter darstellt.

schema.sql


create table department (
    id integer not null primary key,
    name varchar(255) not null);

create table employee (
    id integer not null primary key,
    name varchar(255) not null,
    department_id integer);

Bereiten Sie eine Abteilungsklasse vor, die der Abteilungstabelle entspricht, und eine Mitarbeiterklasse, die der Mitarbeitertabelle entspricht. Die Eigenschaft "Mitarbeiter" wird für die Klasse "Abteilung" und eine Eigenschaft "Abteilung" für die Klasse "Mitarbeiter" bereitgestellt, und "@ Transient" wird mit Anmerkungen versehen, damit bidirektionale Beziehungen ausgedrückt werden können. @ Transient gibt an, dass die Eigenschaft keiner Spalte in der Datenbank zugeordnet werden soll.

Employee.java


@Entity(metamodel = @Metamodel)
public class Department {
  @Id Integer id;

  String name;

  @Transient List<Employee> employees = new ArrayList<>();

  // getter, setter
}

Department.java


@Entity(metamodel = @Metamodel)
public class Employee {

  @Id
  Integer id;

  String name;

  @Column(name = "DEPARTMENT_ID")
  Integer departmentId;

  @Transient Department department;

  // getter, setter
}

Wir werden ein "EmployeeRepository" vorbereiten und dieser Klasse eine Methode hinzufügen, um ein Beispiel zu zeigen.

EmployeeRepository.java


public class EmployeeRepository {

  private final Entityql entityql;

  public EmployeeRepository(Config config) {
    this.entityql = new Entityql(config);
  }
}

Einfacher Join

Ich habe ein Beispiel für einen einfachen Join in einem früheren Artikel [hier] geschrieben (https://qiita.com/nakamura-to/items/77d9e56aff890d7757b3#%E5%90%8C%E7%AD%89%E3%81%) AE% E6% A4% 9C% E7% B4% A2% E7% B5% 90% E6% 9E% 9C% E3% 82% 92join% E5% 8F% A5% E3% 82% 92% E4% BD% BF% E3% 81% A3% E3% 81% A6% E5% AE% 9F% E7% 8F% BE).

Bei einem einfachen Join wird das zugehörige Objekt nicht abgerufen, daher ist eine Eigenschaftsdefinition "@ Transient" nicht unbedingt erforderlich. Abhängig von der Situation können Sie jedoch festlegen, dass das zugehörige Objekt nicht abgerufen werden soll. Daher sollten Sie die Grundlagen definieren.

Beitreten, um verwandte Entitäten zu erhalten

Um die zugehörige Entität zu erhalten, rufen Sie die Methode "leftJoin" oder "innerJoin" und dann die Methode "Associate" auf. Übergeben Sie den Lambda-Ausdruck, um ihn mit der Methode "assoziieren" zu verknüpfen.

  public List<Employee> selectAllWithAssociation() {
    Employee_ e = new Employee_();
    Department_ d = new Department_();
    return entityql
        .from(e)
        .leftJoin(d, on -> on.eq(e.departmentId, d.id))
        .associate(e, d, (employee, department) -> {
            employee.setDepartment(department);
            department.getEmployees().add(employee);
        })
        .fetch();
  }

Die an die "Associate" -Methode übergebenen Lambda-Ausdrücke werden für die Anzahl aller Mitarbeiter aufgerufen. Das auszuführende SQL sieht folgendermaßen aus:

select
    t0_.id,
    t0_.name,
    t0_.DEPARTMENT_ID,
    t1_.id,
    t1_.name
from
    Employee t0_
left outer join
    Department t1_
on
    (t0_.DEPARTMENT_ID = t1_.id)

Sie sehen, dass die Auswahlliste beide Spalten für die Mitarbeitertabelle und die Abteilungstabelle enthält. Da es von SQL1 erworben wurde, tritt das N + 1-Problem nicht auf.

Im obigen Beispiel lesen Sie die Methoden "leftJoin" und "assoziieren" nur einmal, aber beide können in einer einzigen Abfrage mehrmals aufgerufen werden, wie im folgenden Beispielcode.

  public Order selectOrder(int orderId) {
    var order_ = new Order_();
    var orderStatus_ = new OrderStatus_();
    var orderLineItem_ = new OrderLineItem_();
    var item_ = new Item_();
    var inventory_ = new Inventory_();
    var product_ = new Product_();

    return entityql
        .from(order_)
        .innerJoin(orderStatus_, on -> on.eq(order_.orderId, orderStatus_.orderId))
        .leftJoin(orderLineItem_, on -> on.eq(order_.orderId, orderLineItem_.orderId))
        .leftJoin(item_, on -> on.eq(orderLineItem_.itemId, item_.itemId))
        .innerJoin(inventory_, on -> on.eq(item_.itemId, inventory_.itemId))
        .innerJoin(product_, on -> on.eq(item_.productId, product_.productId))
        .where(c -> c.eq(order_.orderId, orderId))
        .associate(order_, orderStatus_, Order::setOrderStatus)
        .associate(order_, orderLineItem_, Order::addLineItem)
        .associate(orderLineItem_, item_, OrderLineItem::setItem)
        .associate(item_, inventory_, Item::setInventory)
        .associate(item_, product_, Item::setProduct)
        .fetchOne();
  }

Dieses Beispiel ist eine Beispiel-App spring-boot-jpetstore Teil -jpetstore / blob / f44df4c6289934d3b5d74ebd1c0172186cb138ef / src / main / java / sample / repository / OrderRepository.java # L25-L47 ) ist.

Sie können es erhalten, indem Sie eine beliebige Anzahl verwandter Ziele ohne besondere Einschränkungen verfolgen. Im obigen Beispielcode können Sie beispielsweise verwandte Entitäten abrufen, indem Sie Order → OrderLineItem → Item → Product folgen. Beachten Sie jedoch, dass die von SQL erfasste Datenmenge in der Regel sehr groß ist.

Wiederverwendung des Assoziationscodes

Wenn Sie eine Abfrage wie die oben beschriebene schreiben, sind Sie möglicherweise besorgt über die Duplizierung des zugeordneten Codes (der Lambda-Ausdruck, der an die Methode "Associate" übergeben wird). In diesem Fall wird empfohlen, den Lambda-Ausdruck als Klasse auszudrücken.

  public List<Employee> selectAllWithAssociation() {
    Employee_ e = new Employee_();
    Department_ d = new Department_();
    return entityql
        .from(e)
        .leftJoin(d, on -> on.eq(e.departmentId, d.id))
        .associate(e, d, new Employees_Department())
        .fetch();
  }

Der Lambda-Ausdruck der "Associate" -Methode ist nur "BiConsumer", sodass Sie eine Implementierungsklasse erstellen können.

public class Employees_Department implements BiConsumer<Employee, Department> {

  @Override
  public void accept(Employee employee, Department department) {
    employee.setDepartment(department);
    department.getEmployees().add(employee);
  }
}

abschließend

Ich habe Ihnen gezeigt, wie Sie Joins in der Doma Criteria API verwenden.

Bei Doma müssen Sie keine statischen Anmerkungen wie "@ OneToMany" statisch in die Entitätsklasse wie JPA schreiben. Daher ist es erforderlich, die Zuordnungsverarbeitung in der Abfrage, die die Kriterien-API verwendet, explizit zu beschreiben, es ist jedoch möglich, diese Abfrage flexibel zu beschreiben.

Im Beispiel dieses Artikels wird die zugehörige Entität durch die Eigenschaft der Entität unter Verwendung von "@ Transient" dargestellt, da dies die häufigste Methode ist. Abhängig von Ihrer Präferenz unterscheidet sich die Entität, die durch den Lambda-Ausdruck der "Associate" -Methode erhalten wird, vollständig. Es ist auch möglich, es im Objekt von zu haben.

Recommended Posts

Erste Schritte mit Doma-Using Joins mit der Criteira-API
Erste Schritte mit der Doma-Projektion mit der Criteira-API
Erste Schritte mit Doma-Einführung in die Kriterien-API
Erste Schritte mit Doma-Dynamic Erstellen von WHERE-Klauseln mit der Kriterien-API
Erste Schritte mit Reactive Streams und der JDK 9 Flow API
Erste Schritte mit dem Doma-Criteria API Cheet Sheet
Beginnen Sie mit der Funktionsweise von JVM GC
Erste Schritte mit DBUnit
Erste Schritte mit Ruby
Erste Schritte mit Swift
Erste Schritte mit Doma-Transaktionen
Erste Schritte mit Doma-using Logical Operators wie AND und OR in der WHERE-Klausel der Criteria-API
Erste Schritte mit der Verarbeitung von Doma-Annotationen
Erste Schritte mit Java Collection
Erste Schritte mit JSP & Servlet
Erste Schritte mit Java Basics
Erste Schritte mit Spring Boot
Erste Schritte mit Ruby-Modulen
Jetzt ist es an der Zeit, mit der Stream-API zu beginnen
Erste Schritte mit Docker mit VS-Code
Zurück zum Anfang, Erste Schritte mit Java ② Steueranweisungen, Schleifenanweisungen
Fassen Sie die wichtigsten Punkte für den Einstieg in JPA zusammen, die Sie mit Hibernate gelernt haben
Erste Schritte mit Ruby für Java-Ingenieure
Erste Schritte mit Docker für Mac (Installation)
Einführung in den Parametrisierungstest in JUnit
Erste Schritte mit Ratpack (4) -Routing & Static Content
Erste Schritte mit dem Language Server Protocol mit LSP4J
Erste Schritte mit dem Erstellen von Ressourcenpaketen mit ListResoueceBundle
Erste Schritte mit Java_Kapitel 8_Über "Instanzen" und "Klassen"
Links & Memos für den Einstieg in Java (für mich)
Erste Schritte mit Java 1 Ähnliche Dinge zusammenstellen
Erste Schritte mit Kotlin zum Senden an Java-Entwickler
Ich habe versucht, mit Gradle auf Heroku zu beginnen
Zurück zum Anfang und erste Schritte mit Java ① Datentypen und Zugriffsmodifikatoren
Erste Schritte mit Java-Programmen mit Visual Studio Code
Erste Schritte mit älteren Java-Ingenieuren (Stream + Lambda)
Beginnen Sie mit serverlosem Java mit dem leichtgewichtigen Framework Micronaut!