使用 JPQL/EntitGraph 加载子实体不适用于 EclipseLink 和 spring 数据
Load subentities with JPQL/EntitGraph is not working with EclipseLink and spring data
我正在尝试使用 EntityGraphs 或 JPQL 创建 1 个 select 而不是许多小的(子)select。但是,子实体会在额外的 select 中加载。
示例:
@NamedEntityGraph( name = "All",
attributeNodes = {
@NamedAttributeNode( value = "bars", subgraph = "subgraph.foobars") },
subgraphs = {
@NamedSubgraph( name = "subgraph.foobars",
attributeNodes = {
@NamedAttributeNode(value = "fooBars", subgraph = "subgraph.foobar"),
@NamedAttributeNode( "mqttEndpoints" ) } ),
@NamedSubgraph( name = "subgraph.foobar",
attributeNodes = {
@NamedAttributeNode( "name" ) } ) })
public class Foo {
@OneToMany( fetch = FetchType.LAZY )
private Set<Bar> bars = Sets.newHashSet();
}
public class Bar {
@OneToMany( fetch = FetchType.LAZY )
private Set<FooBar> fooBars = Sets.newHashSet();
}
public class FooBar {
String name;
}
@EntityGraph( value = "All", type = EntityGraph.EntityGraphType.FETCH )
Optional<Foo> findById( String id);
@Query( "SELECT DISTINCT f FROM foo f"
+ " LEFT JOIN FETCH f.bar bars "
+ " LEFT JOIN FETCH bar.fooBars foobars "
+ " WHERE t.id =:id " )
Optional<Foo> readById( String id);
日志
SELECT ...
FROM foo t1
LEFT OUTER JOIN bars t0 ON (t0.bar_id = t1.id)
SELECT name
FROM foobar
WHERE ...
如果我使用 queryhints 那么它可以与 subselect 一起使用,那有什么问题吗?
https://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/q_left-join-fetch.htm
在休眠模式下效果很好。
您会注意到 EclipseLink 总是对任何关系映射执行额外的查询,除非您指定 fetchJoin 注释(或查询提示,或使用自定义程序修改映射)告诉它要做什么,这与关系被渴望或懒惰地获取。另一方面,Hibernate 将所有渴望访问解释为使用 join。没有必要争论哪个更好 - 它们是视情况而定的,并且有充分的理由将任一解决方案作为通用解决方案。
这意味着,如果您想即时加入 EclipseLink,您需要做的不仅仅是指明需要急切获取关系并包含在查询提示中。如果您要使用获取图来优化事物,那么查看其他获取类型(例如批量获取)可能会有所帮助。额外的 query/statement 对性能而言并不总是坏事,尤其是随着对象图的增长。数据库将被迫 return N*M 行 Foo 数据的重复行,结果中的每个 Bar 和 FooBar 组合对应一个。根据数据大小,在单独的查询中获取子项会更有效。
我正在尝试使用 EntityGraphs 或 JPQL 创建 1 个 select 而不是许多小的(子)select。但是,子实体会在额外的 select 中加载。 示例:
@NamedEntityGraph( name = "All",
attributeNodes = {
@NamedAttributeNode( value = "bars", subgraph = "subgraph.foobars") },
subgraphs = {
@NamedSubgraph( name = "subgraph.foobars",
attributeNodes = {
@NamedAttributeNode(value = "fooBars", subgraph = "subgraph.foobar"),
@NamedAttributeNode( "mqttEndpoints" ) } ),
@NamedSubgraph( name = "subgraph.foobar",
attributeNodes = {
@NamedAttributeNode( "name" ) } ) })
public class Foo {
@OneToMany( fetch = FetchType.LAZY )
private Set<Bar> bars = Sets.newHashSet();
}
public class Bar {
@OneToMany( fetch = FetchType.LAZY )
private Set<FooBar> fooBars = Sets.newHashSet();
}
public class FooBar {
String name;
}
@EntityGraph( value = "All", type = EntityGraph.EntityGraphType.FETCH )
Optional<Foo> findById( String id);
@Query( "SELECT DISTINCT f FROM foo f"
+ " LEFT JOIN FETCH f.bar bars "
+ " LEFT JOIN FETCH bar.fooBars foobars "
+ " WHERE t.id =:id " )
Optional<Foo> readById( String id);
日志
SELECT ...
FROM foo t1
LEFT OUTER JOIN bars t0 ON (t0.bar_id = t1.id)
SELECT name
FROM foobar
WHERE ...
如果我使用 queryhints 那么它可以与 subselect 一起使用,那有什么问题吗? https://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/q_left-join-fetch.htm
在休眠模式下效果很好。
您会注意到 EclipseLink 总是对任何关系映射执行额外的查询,除非您指定 fetchJoin 注释(或查询提示,或使用自定义程序修改映射)告诉它要做什么,这与关系被渴望或懒惰地获取。另一方面,Hibernate 将所有渴望访问解释为使用 join。没有必要争论哪个更好 - 它们是视情况而定的,并且有充分的理由将任一解决方案作为通用解决方案。
这意味着,如果您想即时加入 EclipseLink,您需要做的不仅仅是指明需要急切获取关系并包含在查询提示中。如果您要使用获取图来优化事物,那么查看其他获取类型(例如批量获取)可能会有所帮助。额外的 query/statement 对性能而言并不总是坏事,尤其是随着对象图的增长。数据库将被迫 return N*M 行 Foo 数据的重复行,结果中的每个 Bar 和 FooBar 组合对应一个。根据数据大小,在单独的查询中获取子项会更有效。