[英]DTO projection on a recursive structure
在我的数据模型中,有一个实体“位置”是递归的。 此外,与其他实体也有关系。
相应的JPA(Spring Data JPA)实体看起来像:
@Entity
@Table(name = "location")
class Location{
@OneToMany(mappedBy = "parent", orphanRemoval = true)
@OrderBy("name ASC")
Set<Location> children = null
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
Location parent = null
@Column(name = "name")
String name = null
@OneToMany(mappedBy = "location", fetch = FetchType.EAGER)
Stops stops = null
...
进行只读查询的最有效方式是什么? 我只需要具有完整递归结构的实体(表位置)内部的信息,而无需来自相关实体的信息。
我已经读过DTO投影一词,但与递归结构无关。
读取递归结构通常是通过利用SQL称为递归CTE来完成的 。 JPA不立即支持该功能,因为并非所有RDBMS都支持它。 如果您知道您的DBMS支持它,则可以使用以下SQL来做到这一点:
WITH RECURSIVE nodes(id, parent_id) AS (
SELECT id, parent_id FROM location l where id = ?
UNION ALL
SELECT l.id, l.parent_id FROM nodes n JOIN location l ON n.parent_id = l.id
)
SELECT id, parent_id FROM nodes
这样一来,您将获得一个特定的父级位置ID列表以及它们各自的父级ID。 您将不得不在其中引入结构。
List<Object[]> result = //get the result of the query
Map<Integer, LocationDto> locationMap = new HashMap<>();
result.forEach(r -> locationMap.put(result.get(0), new LocationDto(result[0], result[1])));
locationMap.values().forEach(l -> l.setParent(locaitonMap.get(l.getParentId())));
如果您由于可移植性问题而不想使用纯SQL,或者只是因为不想放弃抽象而使用Blaze-Persistence ,则可以在JPA之上使用Blaze-Persistence ,并增加对CTE的支持。 。 您的查询具有持久性,看起来像这样
List<LocationCte> result = criteriaBuilderFactory.create(entityManager, LocationCte.class)
.withRecursive(LocationCte.class)
.from(Location.class, "l")
.bind("id").select("l.id")
.bind("parent").select("l.parent.id")
.where("id").eq(initialId)
.unionAll()
.from(Location.class, "l")
.innerJoinOn(LocationCte.class, "cte")
.on("cte.parent").eqExpression("l.id)
.end()
.bind("id").select("l.id")
.bind("parent").select("l.parent.id")
.end()
.from(LocationCte.class)
.getResultList();
您还将需要此特殊实体类
@CTE
@Entity
public class LocationCte {
@Id Integer id;
Integer parent;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.