I have spent quite a bit of time reading this great post about OneToMany and ManyToOne relationships.
As a result of that posted I have used the final method described to setup my relationshps - that is to simple annotation the @ManyToOne side and write a JPQL query to retrieve the parent and all the children.
The problem is despite defining fetch = FetchType.LAZY it is still fetching EAGER.
My specific objects are:
@Entity
@Data
public class HealthCeck {
@Id
@GeneratedValue(strategy - IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Patient patient;
// getters and setters
and on the OneTo side:
@Entity
@Data
public class Patient {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
private String name;
// other fields
// getters and setters
When I run my springboot application the table is create similar to
and my JPQL if I need to get a Health_Check with Patient
@Query("select hc from HealthCheck where hc.patient.id = :patientId")
Collection<HealthCheck> findHealthCheckByPatientId(@Param("patientId") Long id);
Now this all works but one thing I do not understand. If I retrieve a HealthCheck (where I have explicitly speicified LAZY loading of patient) instead of just getting the foreign key of patient I get the whole patient object.
Why?
In my application I will build DTOs, but for now I need to be able to retrieve a HealthCheck by Id with only the id number of the patient rather than the whole object.
PS: These objects are being deserialised in Jackson with a REST endpoint and thats where I am seeing the whole patient Object on a HealthCheck.
It was suggested to “reassure” hibernate that for every HealthCheck there is a patient, then hibernate doesn’t feel the need to EAGER load (and override my LAZY).
Are you seeing a second query or a join to patient in your main SQL query for fetching the patient data? Chances are, you are seeing the Patient association populated because the object is in the first or second level cache.
If you see a secondary query, try to determine when this query is issued exactly. It might be that your conversion to a DTO is triggering lazy loading.
I was basing my conclusion that its not LAZY loading on the basis that my REST controller was showing the child and the parent.
But other have suggested that when serialised all the entities are loaded - so looking at the output of the REST controller is not a good way to check if something was LAZY loaded.
(perhaps you know a better place in breakpoint/debugger to check this?)
But this does not mean that I should be attempting setup the relationships on the entity so that a request to the database for a HealthCheck brings back the parent Patient and the related children objects weight.
While the relationships should be defined, and there should be a way to get the parent with the children and visa versa - the object sent to the REST controller should normally be a DTO constructed in a service layer, with only the necessary fields sent for the particular view.
The method name to construct this DTO might be dtoGetHealthCheckwithPatientandWeights() etc?
the object sent to the REST controller should normally be a DTO constructed in a service layer, with only the necessary fields sent for the particular view.
Sounds like a better idea to me. You might find Blaze-Persistence Entity-Views interesting for this use case which I am the author of.
You can share the FK column with the PK, but then you can’t use a FK constraint. To do that, you will also have to annotate the association with @NotFound(action = IGNORE), but I would advise against that if possible. Another alternative is to map this through a secondary table, but either way, Hibernate will have to always join the target table to know if the FK column points to an actual row.