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