3

I have two entities joined by a bidirectional OneToOne-association like this:

@Entity
class Parent {

    @NotNull
    String businessKey;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "child_id")
    @JsonManagedReference
    Child child;

}

@Entity
class Child {

  @JsonBackReference
  @OneToOne(mappedBy = "child", fetch = FetchType.LAZY)
  Parent parent;

}

Background

I'm using Spring Data and CRUDRepository to load the Parent using a generated Query like Parent findByBusinessKey(String businessKey) because the default FetchMode is Eager the Child entity gets fetched by its child_id foreign key in the Parent Table. Eager fetching is no Problm here, because the whole graph gets serialized to json later.

Originally the association was unidirectional and the Child had no reference to its Parent. Unfortunately the Back-reference had to be added and Performance degraded extremely. Logging of generated Sql showed the following Queries (simplified):

select p.id, p.business_key, ..., p.child_id from Parent p where p.business_key = ?;


select c.id, ... from Child c where c.id = ?;

-- here it goes wrong
select p.id, p.business_key, ... from Parent p
   left join OtherEagerJoinedTable t on p.other_id = t.id
   left join AnotherEagerJoinedTable a on p.another_id = a.id
 where p.child_id = ?;

Hibernate seems to fetch the Parent separately from the Database instead of using the already selected instance. This happens for every OneToOne Relation like this (there are a few) with each join query taking up to 200 ms. With unidirectional Mapping the whole Entity Graph was queried in less than 100 ms.

Questions

How can i tell Hibernate that the Parent Entity already exists and the fetch is not needed? I tried optional=false in Child entity but it didn't help.

Versions

I'm currently using hibernate 5.2.12 and Spring Boot 1.2.8. Unfortunately Update of Versions is currently not an option. Also even if changes on the DB side are still possible it would require relatively large refactoring effort in other places. I just need to tell hibernate not to eagerly fetch the parent reference from Db. Maybe an EntityGraph could help with that but I have not used them yet and now not much about it.

see also

Any help is appreciated

ProfDrM
  • 43
  • 6

1 Answers1

1

This will be the case with @OneToOne mapping. I have been there, done that. To get past through that you would have to implement bytecode enhancement on Hibernate dirty checking mechanism and change parent side not to use proxy (annotation : @LazyToOne(LazyToOneOption.NO_PROXY)).

Please refer to Vlad Mihalcea's article describing exactly your case I think

In that article you will also find a link to anothere useful Vlad's article - an information how to implement the bytecode enhancement

Przemek
  • 223
  • 1
  • 8
  • I also stumbled upon this post but thought I could get arround this by the correct annotation. But I guess I give the Bytecode Version a try and see if it works – ProfDrM Dec 16 '20 at 11:44
  • Bytecode enhancement worked for me, but with the drawback of needing maven to compile Instead of the faster Intellij built in compiler (at least for local development) – ProfDrM Dec 17 '20 at 17:28