[JAVA] Premiers pas avec Doma-Using Joins avec l'API Criteira

introduction

Doma Décrit comment utiliser les jointures avec l'API 2.43.0 Criteria.

L'API Criteira de Doma prend en charge deux modèles: "simplement rejoindre" et "rejoindre et obtenir des entités associées". Ce dernier est un peu comme le join fetch de JPA en termes d'implications.

Pour un aperçu de Doma et de l'API Criteria, lisez les autres articles dans Introduction à Doma.

Exemple de code utilisé dans cet article

Voici un code simplifié. Voir le projet ci-dessous pour l'exemple de code complet.

La base de données a une table de service qui représente les services et une table d'employé qui représente les employés.

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);

Préparez une classe Department correspondant à la table Department et une classe Employee correspondant à la table Employee. Une propriétéemployees est fournie pour la classe Department et une propriété department est fournie pour la classe Employee, et «@ Transient» est annoté afin que les relations bidirectionnelles puissent être exprimées. «@ Transient» indique que la propriété ne doit pas être mappée à une colonne de la base de données.

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
}

Nous préparerons ʻEmployeeRepository` et ajouterons une méthode à cette classe pour montrer un exemple.

EmployeeRepository.java


public class EmployeeRepository {

  private final Entityql entityql;

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

Jointure simple

J'ai écrit un exemple de jointure simple dans un article précédent [ici](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% 92 jointure% E5% 8F% A5% E3% 82% 92% E4% BD% BF% E3% 81% A3% E3% 81% A6% E5% AE% 9F% E7% 8F% BE).

Une simple jointure n'obtient pas l'objet associé, donc une définition de propriété @ Transient n'est pas essentielle, mais en fonction de la situation, vous pouvez choisir de ne pas obtenir l'objet associé, donc je pense que vous devriez définir les bases.

Rejoignez-nous pour obtenir des entités associées

Pour obtenir l'entité associée, appelez la méthode leftJoin ou ʻinnerJoin puis la méthode ʻassociate. La méthode ʻAssociate` reçoit une expression lambda à associer.

  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();
  }

Les expressions lambda passées à la méthode ʻassociate` sont appelées pour le nombre de tous les employés. Le SQL à exécuter ressemble à ceci:

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)

Vous pouvez voir que la liste de sélection contient les deux colonnes pour la table des employés et la table des départements. Puisqu'il est acquis à partir de SQL1, le problème N + 1 ne se produit pas.

Dans l'exemple ci-dessus, nous ne lisons qu'une seule fois les méthodes leftJoin et ʻassociate`, mais les deux peuvent être appelées plusieurs fois dans une seule requête, comme dans l'exemple de code ci-dessous.

  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();
  }

Cet exemple est un exemple d'application spring-boot-jpetstore part -jpetstore / blob / f44df4c6289934d3b5d74ebd1c0172186cb138ef / src / main / java / sample / repository / OrderRepository.java # L25-L47 )est.

Vous pouvez l'obtenir en traçant n'importe quel nombre de destinations associées sans aucune restriction particulière. Par exemple, dans l'exemple de code ci-dessus, vous pouvez obtenir des entités associées en suivant Order → OrderLineItem → Item → Product. Cependant, veuillez noter que la quantité de données acquises par SQL a tendance à être importante.

Réutilisation du code d'association

Si vous écrivez une requête comme celle ci-dessus, vous pouvez être préoccupé par la duplication du code associé (l'expression lambda passée à la méthode ʻassociate`). Dans ce cas, il est recommandé d'exprimer l'expression lambda en tant que classe.

  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();
  }

L'expression lambda de la méthode ʻassociate est simplement BiConsumer`, vous pouvez donc créer une classe d'implémentation.

public class Employees_Department implements BiConsumer<Employee, Department> {

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

en conclusion

Je vous ai montré comment utiliser les jointures dans l'API Criteria de Doma.

Doma ne vous oblige pas à écrire statiquement des annotations liées telles que @ OneToMany dans la classe d'entité comme JPA. Par conséquent, il est nécessaire de décrire explicitement le traitement d'association dans la requête qui utilise l'API Criteria, mais il est possible de décrire de manière flexible pour chaque requête.

Dans l'exemple de cet article, l'entité associée est représentée par la propriété de l'entité utilisant «@ Transient» car c'est la méthode la plus courante, mais selon vos préférences, l'entité obtenue par l'expression lambda de la méthode «associate» est complètement différente. Il est également possible de l'avoir dans l'objet de.

Recommended Posts

Premiers pas avec Doma-Using Joins avec l'API Criteira
Premiers pas avec Doma-Using Projection avec l'API Criteira
Premiers pas avec les sous-requêtes utilisant Doma avec l'API Criteria
Premiers pas avec Doma - Introduction à l'API Criteria
Premiers pas avec Doma-Dynamic Construction de clauses WHERE avec l'API Criteria
Premiers pas avec Reactive Streams et l'API JDK 9 Flow
Premiers pas avec Doma-Criteria API Cheet Sheet
Démarrez avec le fonctionnement de JVM GC
Premiers pas avec DBUnit
Premiers pas avec Ruby
Premiers pas avec Swift
Premiers pas avec Doma-Transactions
Prise en main des opérateurs logiques utilisant Doma tels que AND et OR dans la clause WHERE de l'API Criteria
Premiers pas avec le traitement Doma-Annotation
Premiers pas avec Java Collection
Premiers pas avec JSP et servlet
Premiers pas avec les bases de Java
Premiers pas avec Spring Boot
Premiers pas avec les modules Ruby
Il est maintenant temps de commencer avec l'API Stream
Premiers pas avec Docker avec VS Code
Revenir au début, démarrer avec Java ② Instructions de contrôle, instructions de boucle
Résumer les principaux points de démarrage avec JPA appris avec Hibernate
Premiers pas avec Ruby pour les ingénieurs Java
Premiers pas avec Docker pour Mac (installation)
Introduction au test de paramétrage dans JUnit
Premiers pas avec Ratpack (4) - Routage et contenu statique
Premiers pas avec Language Server Protocol avec LSP4J
Premiers pas avec la création d'ensembles de ressources avec ListResoueceBundle
Premiers pas avec Java_Chapter 8_A propos des "Instances" et des "Classes"
Liens et mémos pour démarrer avec Java (pour moi-même)
Premiers pas avec Java 1 Assembler des éléments similaires
Premiers pas avec Kotlin à envoyer aux développeurs Java
J'ai essayé de démarrer avec Gradle sur Heroku
Revenir au début et démarrer avec Java ① Types de données et modificateurs d'accès
Prise en main des programmes Java à l'aide de Visual Studio Code
Premiers pas avec les anciens ingénieurs Java (Stream + Lambda)
Commencez avec Java sans serveur avec le framework léger Micronaut!