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