Cosium / spring-data-jpa-entity-graph

Spring Data JPA extension allowing full dynamic usage of EntityGraph on repositories
MIT License
469 stars 52 forks source link

Original findById not using graph #33

Closed ghost closed 4 years ago

ghost commented 4 years ago

Hello, I have just tried creating a project very similar to your example: https://github.com/Cosium/spring-data-jpa-entity-graph/blob/master/doc/MAIN.md and I found that when I try to use the original findById method from the EntityGraphCrudRepository, it would not use the default graph. It would also not work if I dynamically call my default graph like so: findById(1L, EntityGraphs.named("Product.default"));

Other custom methods like findByNameAndLastName will use the default like expected.

This behavior seems like it has something to do with updating an entity, or rather, calling save into an entity that already has an id.

When I save my entity for the first time, like product = prodRepo.save(prod), the default graph is used correctly. If I then immediately change something in that entity and save it again, I see the graph not being used.

            Product prod = new Product();
            prod.setName("Test");
            prod= prodRepository.save(prod); //Default graph used
            prod= prodRepository.findById(prod.getId()).get();  //Default graph used

            prod.setName("Test2");
            prod= prodRepository.save(prod);  //Default graph NOT used
            prod= prodRepository.findById(prod.getId()).get();  //Default graph NOT used
            prod= prodRepository.findById(prod.getId(), EntityGraphs.named("Product.default")).get();  //Default graph NOT used

Thank you very much for your help.

reda-alaoui commented 4 years ago

Hello @NRosenbergLoyaltyOne ,

Please provide a repository or a test allowing to reproduce your issue.

ghost commented 4 years ago

Hi @reda-alaoui , thanks for the response. I have added an example of how to reproduce based on the examples you have on the github. Is that enough?

reda-alaoui commented 4 years ago

JPA specification expects EntityGraph to be used by queries only, never by saves.

What follows is an Hibernate behaviour: findById pulls the product from the cache when possible. When it does, it never uses an EntityGraph. So the first findById doesn't find product in the cache, it then performs the query with the EntityGraph. Subsequent queries find the product in the cache, therefore no EntityGraph is applied. If you perform entityManager.clear() between the first and second findById, you will see that the EntityGraph is used during the second findById.

ghost commented 4 years ago

I see, not the first time I get caught by hibernate doing things I am not clear about.

Is the cache cleared after the transaction ends? If the first findById is done in one method, and the next in another method, will the behavior be the same?

What would then be the best way to ensure I get the joined entities back when doing a save?

Thank you for your time.

reda-alaoui commented 4 years ago

Is the cache cleared after the transaction ends?

Yes

If the first findById is done in one method, and the next in another method, will the behavior be the same?

If both methods are running in the same transaction, the behaviour will be the same.

What would then be the best way to ensure I get the joined entities back when doing a save?

Your example does not expose entities loaded by product. If the entity referenced by Product is attached to the current Hibernate session, it should be loaded.