gpt4 book ai didi

java - Hibernate LEFT JOIN FETCH 带 ON 子句或替代

转载 作者:行者123 更新时间:2023-12-02 19:00:22 25 4
gpt4 key购买 nike

我有亲子关系。

父类具有以下字段(id, name),子类具有以下列(id, name, date, parent_id)。我要返回的最终结果 JSON 如下。我也总是想返回父级,即使它没有子级,这就是为什么我在子级上使用 ON 子句LEFT OUTER JOIN

[

{
"name": "parnet1",
"child": {
"2021-01-01": {
"name": "child1"
},
"2021-01-02": {
"name": "child2"
}
}
},
{
"name": "parnet2",
"child": {}
}
}
]

此示例中我的数据库的示例

parent

id    |     name
1 | parent 1
2 | parent 2

child

id    |     name    |    date    |    parent_id
1 | child1 | 2021-01-01| 1
2 | child2 | 2021-01-02| 1
3 | child3 | 2020-12-31| 2

对于以下示例,我将传递 2021-01-01 的数据

所以月份是一月 (1) 年是 2021

在父类中我有一张 map 来引用 child

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JsonManagedReference
@MapKey(name = "date")
private Map<LocalDate, Child> children;

这是我的查询

@Query("select p from Parent p left join p.child c on YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMonth

这个问题是 hibernate 后自动运行的第二个查询如下:

select * from Child where c.parent_id = ?

这最终会得到连接条件不正确的所有 child 。

然后我尝试了这个

 @Query("select new Parent(p.id, p.name, c.id, c.date, c.name) from Parent p left join p.child c on YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMonth

并制作了这个构造函数

public Parent(int id, String name, int childId, LocalDate date, String childName) {

this.id = id;
this.name = name;
this.children = new HashMap<LocalDate, Child>();
if (childId != null) {
Child child = new Child();
child.setId(id);
child.setName(name);
this.children.put(date, child);
}
}

但问题是,当我希望数组的顶层长度为 2 时,我得到了一个长度为 4 的 JSON 数组,因为目前数据库中只有 2 个父级。

我如何修改它以获得我想要的 JSON 负载,它发布在问题的顶部。

非常感谢

编辑

如果我要传入 date = '2021-01-01',则使用以下内容不起作用,因为不会返回 child2

select distinct p from Parent p 
left join fetch p.children c
where (YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMont)
or c.parent is null

编辑 2(关于自动生成的查询)

我正在使用 spring boot 作为 API 运行它,但没有额外的处理,这是我的 API 和当前查询。

@GetMapping(path = "/parents/{date}", produces = { "application/json" })
@Operation(summary = "Get all parents for date")
public @ResponseBody List<Parent> getParentsByDate(@PathVariable("date") String dateString) {

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate dateOccurred = LocalDate.parse(dateString, formatter);

return parentRepository.getParentsForDate(dateOccurred);


}

然后在我的存储库中,我只有我的@Query,这是我目前在 ParentRepository 类中的内容

public interface ParentRepository extends CrudRepository<Parent, Integer> {

@Query("select p from Parent p left join fetch p.children c where (YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMonth) or c.parent is null")
public List<Parent> getParentsForDate(@Param("dateOccurred") LocalDate dateOccurred
}

但如前所述,这个问题是空检查确实工作正常,如果 parent 在另一个月有任何 child ,但不是当前的 child ,则不会返回 parent

最佳答案

解决方案:


我找到了 join 操作的获取和多条件解决方案:我们可以应用 EntityGraph 特性:

@NamedEntityGraph(name = "graph.Parent.children", attributeNodes = @NamedAttributeNode("children"))
public class Parent {
...
}

并且在存储库中,您需要将此 EntityGraphQuery 链接起来,如下所示:

...
@Query("select distinct p from Parent p left join p.children c on YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMont")
@EntityGraph(value = "graph.Parent.children")
List<Parent> findAllParents(Integer dateYear, Integer dateMont);
...

以前的解决方案:


如您所知,Hibernate 不允许在 on 中为 fetch join 使用多个条件,因此:with-clause not allowed on fetched协会;使用过滤器 异常,因此我建议使用以下 HQL 查询:

select distinct p from Parent p 
left join fetch p.children c
where (YEAR(c.date) = :dateYear and MONTH(c.date) = :dateMont)
or c.parent is null

注意:distinct 是避免父实体重复所必需的,关于它有文章:https://thorben-janssen.com/hibernate-tips-apply-distinct-to-jpql-but-not-sql-query/

因此,Hibernate 将生成一个支持没有 child 的 parent 的查询,如果 child 应该像发布的 json 示例中那样排序,您需要为 children 添加 @SortNatural > 领域:

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JsonManagedReference
@MapKey(name = "date")
@SortNatural
private Map<LocalDate, Child> children;

结果,json 将与发布的相同。

作为建议:不要在运行时使用计算值,因为这些操作不能应用索引,在你的情况下我建议使用虚拟列(如果是 Mysql)或仅使用准备好的单独索引列搜索值,并尝试通过索引连接表,这些建议将加快您的查询执行速度。

关于java - Hibernate LEFT JOIN FETCH 带 ON 子句或替代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65649418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com