my2iu / Jinq

LINQ-style queries for Java 8
Other
659 stars 71 forks source link

toList() commit transaction ignoring JPA-Transactional #100

Closed gallusenrico closed 2 years ago

gallusenrico commented 2 years ago

Case

I'm using a Service-Method, which is marked with the SpringBoot-Transactional annotation. In the Service-method the following business-logic is executed.

  1. get a parent-entity using JPA
  2. create child entities and add them to the parent-entity (I do not save them, because they are marked as cascaded)
  3. use Jinq to do a query on unrelated entities
  4. do more business logic
  5. save the parent-entity using JPA

Expected Outcome

I would expect that the ids of the child-entities are assigned in step 5 when the parent entity gets saved using JPA. And with the save-routine cascading assign Id's.

Outcome

What happens instead is that as soon as the Jinq-query calls the toList(), the child entities get their ids assigned. The behavior was spotted because somehow the child entities are loaded redundant with their IDs assign on the parent Entity. But I suppose this is a Hibernate-Issue and does not relate to Jinq.

Used versions

Preconditions

Using a Parent - Child entity definition. Parent definition:

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childs = new ArrayList<>();

Child definition:

@ManyToOne(fetch = FetchType.LAZY)
private Parent parent;

Approache to solve the issue

I did configure Jinq with JPA as described over here. Because I thought it might be a problem with JPA, I extract the Query and called it directly in the service-method. It did change nothing. As soon as the toList() of an unrelated Query is called and the results are loaded, id's are assigned to all the childs added to the parent-entity childs-collection.

my2iu commented 2 years ago

I don’t know. Could it be a weird entity manager issue? Are you using the same entity manager in the Jinq query that you’re also using for your other JPA calls? And what do you mean by IDs assigned? Are the IDs assigned by the database or by JPA? If they’re assigned by JPA, then JPA might create IDs at any time if needed to make things consistent?

gallusenrico commented 2 years ago

Thank you so much for your fast response.

Could it be a weird entity manager issue? Are you using the same entity manager in the Jinq query that you’re also using for your other JPA calls?

The EntityManager used for JPA calls and Jinq queries is the same one.

And what do you mean by IDs assigned? Are the IDs assigned by the database or by JPA? If they’re assigned by JPA, then JPA might create IDs at any time if needed to make things consistent?

I'm using @GeneratedValue(strategy = GenerationType.IDENTITY) so Id's are generated by the DBMS.

I dug deeper into the Query-Execution of Jinq and I recognized that the behaviour has nothing to do with Jinq. The list-method of the SessionImpl-class of hibernate which is called by Jinq does an auto-flush. The query is executed within a transaction, which triggers an auto-flush and assign id's to all dirty entities. So looks like this is an expected behaviour of hibernate.

Again, thank you very much for your response. I really like Jinq! It's an amazing framework.

my2iu commented 2 years ago

If you find that you need some sort of Jinq backdoor or query hint for configuring the Session to disable this autoflush, just reopen the issue, and I can add that in.