懒加载与规范不起作用

huangapple go评论104阅读模式
英文:

Lazy loading not working with Specification

问题

已经迁移到Spring v2.1.2.RELEASE,并使用Hibernate版本5.3.7.FINAL。

我们在实体之间有一个@OneToOne双向关系,如下所示:

  1. class Parent {
  2. @OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
  3. @NotAudited
  4. private Child child;
  5. @Id
  6. @GeneratedValue(strategy = GenerationType.IDENTITY)
  7. private Integer id;
  8. }
  9. class Child {
  10. @OneToOne(fetch = FetchType.LAZY)
  11. @JoinColumn(name = "parent_id")
  12. @MapsId
  13. @NotNull
  14. private Parent parent;
  15. @Id
  16. @Column(name = "indent_id", insertable = false, updatable = false)
  17. private Integer parentId;
  18. }

调用:

  1. parentRepository.findByIdIn(Collections.singletonList(1));

会生成以下数据库调用:

  1. Hibernate:
  2. select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)

这个部分工作正常,现在考虑下面的用例:

  1. public class Filter implements Specification<Parent> {
  2. @Override
  3. public Predicate toPredicate(Root<Indent> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
  4. // TODO Auto-generated method stub
  5. List<Integer> parentIdList = new ArrayList<>();
  6. parentIdList.add(1);
  7. ArrayList<Predicate> predicates = new ArrayList<>();
  8. predicates.add(root.get("id").in(parentIdList));
  9. return predicates.size() == 0 ? null
  10. : criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
  11. }
  12. }
  13. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.Direction.DESC, "id");
  14. Filter filter = new Filter();
  15. Page<Indent> indentPage = indentRepository.findAll(filter, pageRequest);

会生成对Child实体的数据库调用:

  1. Hibernate:
  2. select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
  3. select child0_.parent_id as parent_i1_29_ from child child0_ where child0_.indent_id in (?)

有没有办法避免在这里对Child实体进行数据库调用?

英文:

I have migrated to spring v2.1.2.RELEASE and using hibernate version 5.3.7.FINAL

We have @OneToOne bi directional relationship between entity as follows

  1. class Parent{
  2. @OneToOne(fetch = FetchType.LAZY, mappedBy = &quot;parent&quot;, optional = false)
  3. @NotAudited
  4. private Child child;
  5. @Id
  6. @GeneratedValue(strategy = GenerationType.IDENTITY)
  7. private Integer id;
  8. }
  9. class Child{
  10. @OneToOne(fetch = FetchType.LAZY)
  11. @JoinColumn(name = &quot;parent_id&quot;)
  12. @MapsId
  13. @NotNull
  14. private Parent parent;
  15. @Id
  16. @Column(name = &quot;indent_id&quot;, insertable = false, updatable = false)
  17. private Integer parentId;
  18. }

calling

  1. parentRepository.findByIdIn(Collections.singletonList(1));

makes db call as:
Hibernate:

  1. select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)

Which is working fine, now consider use case,

  1. public class Filter implements Specification&lt;Parent&gt; {
  2. @Override
  3. public Predicate toPredicate(Root&lt;Indent&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder criteriaBuilder) {
  4. // TODO Auto-generated method stub
  5. List&lt;Integer&gt; parentIdList = new ArrayList&lt;&gt;();
  6. parentIdList.add(1);
  7. ArrayList&lt;Predicate&gt; predicates = new ArrayList&lt;&gt;();
  8. predicates.add(root.get(&quot;id&quot;).in(parentIdList));
  9. return predicates.size() == 0 ? null
  10. : criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
  11. }
  12. }
  13. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.Direction.DESC, &quot;id&quot;);
  14. Filter filter = new Filter();
  15. Page&lt;Indent&gt; indentPage = indentRepository.findAll(filter, pageRequest);

makes DB call to Child entity as well

  1. Hibernate:
  2. select parent0_.id as id1_19_ from parent parent0_ where parent0_.id in (?)
  3. select child0_.parent_id as parent_i1_29_ from child child0_ where child0_.indent_id in (?)

Is there any way to avoid Db call to child entity here?

答案1

得分: 1

可以定义一个实体图来指定一个模式,该模式可以传递给查询,以确定要获取哪些属性。图中未包含的属性将被持久化提供程序视为延迟加载(LAZY)。

  1. @Entity
  2. @NamedEntityGraph(name = "only_id", attributeNodes = {@NamedAttributeNode("id")})
  3. class Parent {
  4. @OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
  5. @NotAudited
  6. private Child child;
  7. @Id
  8. @GeneratedValue(strategy = GenerationType.IDENTITY)
  9. private Integer id;
  10. }

JPA API:

  1. EntityGraph entityGraph = entityManager.getEntityGraph("only_id");
  2. // 定义你的查询
  3. query.setHint("javax.persistence.fetchgraph", graph);

更多详情:https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm

使用 Spring Data JPA:

  1. public interface MyRepository extends JpaRepository<Parent, Integer> {
  2. @EntityGraph(value = "only_id")
  3. Parent findById(Integer id);
  4. }

更多详情:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-graph

JpaSpecificationExecutor:

  1. public interface MyRepository extends JpaSpecificationExecutor<Parent> {
  2. @Override
  3. @EntityGraph(attributePaths = {"only_id"}, type = EntityGraphType.FETCH)
  4. Parent findOne(Specification<Parent> spec);
  5. }

更多详情:https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html

英文:

You can define an entity graph to specify a pattern that can be passed to a query to determine which attributes you want to be fetched. Attributes that are not included in the graph will be treated as LAZY by persistence provider.

  1. @Entity
  2. @NamedEntityGraph(name = &quot;only_id&quot;, attributeNodes={@NamedAttributeNode(&quot;id&quot;)})
  3. class Parent{
  4. @OneToOne(fetch = FetchType.LAZY, mappedBy = &quot;parent&quot;, optional = false)
  5. @NotAudited
  6. private Child child;
  7. @Id
  8. @GeneratedValue(strategy = GenerationType.IDENTITY)
  9. private Integer id;
  10. }

JPA API:

  1. EntityGraph entityGraph = entityManager.getEntityGraph(&quot;only_idh&quot;);
  2. // define your query
  3. query.setHint(&quot;javax.persistence.fetchgraph&quot;,graph);

More details : https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm

With Spring Data JPA

  1. public interface MyRepository extends JpaRepository&lt;Parent, Integer&gt; {
  2. @EntityGraph(value = &quot;only id&quot;)
  3. Parent findById(Integer id)

More details : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.entity-graph

JpaSpecificationExecutor :

  1. public interface MyRepository extends JpaSpecificationExecutor&lt;Parent&gt; {
  2. @Override
  3. @EntityGraph(attributePaths = {&quot;only_id&quot;}, type=EntityGraphType.FETCH)
  4. Parent findByOne(Specification&lt;Parent&gt; spec);
  5. }

More details : https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html

答案2

得分: 0

JPA提供程序通常将fetch类型设置为Lazy作为提示,因此在您的情况下可能根本不考虑它。请查看以下内容:

fetch public abstract FetchType fetch(可选)定义字段或属性的值是否应该懒加载还是必须立即提取。EAGER策略是对持久性提供程序运行时的要求,必须立即提取值。LAZY策略是对持久性提供程序运行时的提示。如果未指定,默认为EAGER。默认值:EAGER

JPA文档

英文:

JPA provider usually takes fetch type Lazy as a hint, so may be in your case its not considering it at all. check below

> fetch public abstract FetchType fetch (Optional) Defines whether the
> value of the field or property should be lazily loaded or must be
> eagerly fetched. The EAGER strategy is a requirement on the
> persistence provider runtime that the value must be eagerly fetched.
> The LAZY strategy is a hint to the persistence provider runtime. If
> not specified, defaults to EAGER. Default: EAGER

JPA Doc

huangapple
  • 本文由 发表于 2020年8月8日 20:40:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/63315523.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定