-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot add entity to lazy loaded collection with Quarkus Reactive Panache - org.hibernate.LazyInitializationException #23757
Comments
/cc @FroMage, @Sanne, @gsmet, @loicmathieu, @yrodiere |
Might be related to this hibernate/hibernate-reactive#663 |
This should work:
The problem is that one needs to fetch lazy associations explicitly when using Hibernate Reactive. You could also use the Hibernate Reactive
|
@DavideD oh, thank you. In my real-world application, my entity has two ManyToOne relations that have to be updated at the same time. This means I'd have to explicitly fetch two collections sequentially, waiting for both to complete and only then persist the child. It sounds complicated to me and I would have no clue how to do that, but this got me to rethink if Hibernate is the right choice.... I think I just go with plain SessionFactory and skip the fetching of the collections, which is unnecessary anyway. I just want to insert and don't care about the child. Thank you anyway, I keep that solution in mind for the next time :) |
You know, I think this might be a bug in Hibernate Reactive. We should be able to notice that in this case one doesn't need an additional query for the association and a reference to the parent is what we need. By the way, this is not what the docs say but, unofficially, in this specific case, it should work if you only update the owning side of the association, like this:
Updating both sides of the association is the correct approach, though. |
I will keep this issue open because I want to check what's going on |
Just for completeness, I haven't tested it, it was just an assumption based on the Mutiny.fetch call that I'd have to do it two times before I could do what I wanted to do. |
You need to call fetch for all the lazy associations you intend to update, but in this case it shouldn't result in a query on the db because the info on the child should be enough. I need to check what happens in Hibernate ORM |
I've created an issue for Hibernate Reactive: hibernate/hibernate-reactive#1207 |
Is there a final solution for this? 1207 is closed in hibernate-reactive. But as of latest releases of Quarkus, you still have to manually fetch the relationships. This further breaks when you return Entities in rest responses where the fetching does not occur and you get the error: Fetch the collection using 'Mutiny.fetch', 'Stage.fetch', or 'fetch join' in HQL |
I don't know why this issue is still open, I will have a second look at it later. hibernate/hibernate-reactive#1207 was a performance issue, it doesn't affect the LazyInitializationException.
With Hibernate Reactive, there is no alternative to eagerly load associations or fetching them when needed. Briefly, the problem is that associations are declared as non async types in an entity, for example We could have some custom classes to map associations, but, a user will have to do something similar to what happens now with the Maybe in the future we will come up with something cleverer. |
I'm going to close this issue: Note that Hibernate Reactive has several different ways to load an association eagerly and which one is better depends on the use case. Loading an entity with a join fetch query or using an entity graph is usually the best approach because it will load everything using a single query. |
I feels like the current default config of reactive handling in quarkus for lazy joins is problematic for default serialization: When you do something with panache such as: |
@DavideD see above |
Shouldn't one serialize the object only after the association has been fetched? Or, as you said, you can ignore the association for serialization. What's the use case you have in mind? |
Basically, one solution would be to have:
but you can also use a projection (basically, you use a DTO that doesn't have the association):
But yeah, before seirialization you need to make sure that all the data you need has been fetched. |
If you create a simple entity with a lazy join and return it in a rest controller it fails by default. If the join was not fetched IMO it should not return in the serialization (equiv of doing JsonIgnore). It leads to having to add more complex configs such as JsonViews and other "tricks" to prevent the error. having to explicitly add JSON ignore then becomes problematic because what happens when you do fetch it and want to return the value. Seems like you would then have to apply: |
also given that Joins are lazy by default it becomes additional configs that need to be "always added" or else you get the LazyInitializationException |
I mean, if you know that you always need it, you can map it as EAGER. I suppose we could assume that if the association is an uninitialize proxy, than it doesn't need to be serialized (not sure if it's doable though).
Much better than returning an empty result and than having to figure out why the association doesn't appear in the JSON. |
I also think it's reasonable to have a separate class to map a JSON response if the entity doesn't fit your use case. I expect this to be the most common scenario actually. |
I agree those are the scenarios that complex impl end up creating as they need all of the various projections. But by default and from the examples: https://quarkus.io/guides/hibernate-orm-panache#writing-a-jax-rs-resource, the moment you use Reactive and add a default join, the rest request fails. :) |
¯_(ツ)_/¯ You are basically asking the library to pick for you:
Throwing an error we tell the developer that there's something missing and they need to decide what they want to do. |
We should improve the guide and add this example if it's not included already, though |
Thanks for the feedback. |
Describe the bug
When I'm trying to insert into a child collection of type OneToMany, I'm running into this error:
I've tried multiple ways of inserting, and all result in the same behavior. Also tried using Mutiny.SessionFactory with no change.
Results in error:
How to Reproduce?
Reproducer: https://github.com/mklueh/quarkus-reproducer-insert-into-lazy-collection
Quarkus version or git rev
2.7.1
Am I missing something crucial or is this a bug?
The text was updated successfully, but these errors were encountered: