How hibernate\spring fetches entites in jparepository save method?

Hi all!

I have an entity Order with two identicaly one-to-many relations history and documents.
I make test using postman by sending plain order object(without history and documents )
like {“id” : “1”, “date”:“somedate”} and then just pass this object from controller to service where it just call orderrepository(extends spring jparepository).save(order)
and from sql logs I see that hiernate first executes a select statement where it creates a left outer join from order to documents.
Why so? i expect it to select both relations and also fetch history with order or not to select both at all.
It seems a little bit strange… and by the way in logs i see that it selects document.id and its order.id two times:

select order.id, order.date, order.status 
docs.order_id as order_8_0_3_, 
docs.id as id1_0_3_, 
docs.id as id1_0_0_, 
docs.content_type, 
docs.file_name, 
docs.order_id as order_8_0_0_, 
from tbl_order order left outer join tbl_docs docs on order.id=docs.order_id 
where order.id=?

both entities are mapped as
OneToMany(mappedBy = “order”, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List history = new ArrayList<>();

OneToMany(mappedBy = “order”, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List history = new ArrayList<>();

Spring usually uses EntityManager#merge when you provide an id value in the entity, so Hibernate will load all associations which do MERGE cascading.

Hibernate 5 has a limitation when it comes to using the same foreign key target column for multiple associations, where it only join fetches the first association. Further associations are select fetched, but only if the first query returned results. Since you don’t see a second query, this means that the first query didn’t return results, hence the Order does not exist yet and Hibernate instead does a persist.

In Hibernate 6, this limitation is lifted and you will see both joins. Overall, I would still suggest you try to be explicit about persist/merge i.e. use persist when you definitely want to create a new object, or even use the StatelessSession API which only knows insert or update and does less loading.