1

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

class Parent{

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
    @NotAudited
    private Child child; 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
}

class Child{
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    @MapsId
    @NotNull
    private Parent parent;

    @Id
    @Column(name = "indent_id", insertable = false, updatable = false)
    private Integer parentId;

}

calling

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

makes db call as: Hibernate:

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

Which is working fine, now consider use case,

public class Filter implements Specification<Parent> {

        @Override
        public Predicate toPredicate(Root<Indent> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
            // TODO Auto-generated method stub
            List<Integer> parentIdList = new ArrayList<>();
            parentIdList.add(1);
            ArrayList<Predicate> predicates = new ArrayList<>();
            predicates.add(root.get("id").in(parentIdList));
            return predicates.size() == 0 ? null
                    : criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));

        }

    } 



    PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.Direction.DESC, "id");
    Filter filter = new Filter();
    Page<Indent> indentPage = indentRepository.findAll(filter, pageRequest);

makes DB call to Child entity as well

Hibernate:
select parent0_.id as id1_19_ from  parent parent0_ where parent0_.id in (?)
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
  • The issue was with hibernate version I mentioned and fixed in 5.4 compile group: ‘org.hibernate’, name: ‘hibernate-core’, version: ‘5.4.0.Final’ Commented Aug 20, 2020 at 5:12

2 Answers 2

1

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.

    @Entity
    @NamedEntityGraph(name = "only_id", attributeNodes={@NamedAttributeNode("id")})
    class Parent{
    
        @OneToOne(fetch = FetchType.LAZY, mappedBy = "parent", optional = false)
        @NotAudited
        private Child child; 
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
    }

JPA API:

EntityGraph entityGraph = entityManager.getEntityGraph("only_idh");
// define your query
query.setHint("javax.persistence.fetchgraph",graph);

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

With Spring Data JPA

 public interface MyRepository extends JpaRepository<Parent, Integer> {
 
    @EntityGraph(value = "only id")
    Parent findById(Integer id)

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

JpaSpecificationExecutor :

public interface MyRepository extends JpaSpecificationExecutor<Parent> {
   @Override
   @EntityGraph(attributePaths = {"only_id"}, type=EntityGraphType.FETCH)
   Parent findByOne(Specification<Parent> spec);
}

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

Sign up to request clarification or add additional context in comments.

3 Comments

In the above question, with named method query child entity is lazy loaded but when filter is used child entity is eagerly loaded, How can I achieve lazy loading of child entity with specification?
@atul Please see updated answer above, - You would need to extend JpaSpecificatinExecutor.
Child entity is still called even after: @EntityGraph(attributePaths = {"id"},type = EntityGraphType.FETCH) Page<Parent> findAll(@Nullable Specification<Parent> spec, Pageable pageable);
0

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

1 Comment

Rather than pointing on whole documentation you can quote specific paragraph that made you think of such statement. However, link on the whole docs should be left as refference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.