I have an entity which contains:
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment") @OrderBy(value = "order ASC") private List<AssessmentPart> assessmentParts = new LinkedList<>(); @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "assessment") private List<AssessmentText> texts = new LinkedList<>();
as you see there are two collections which needs to be eagerly loaded. This is not working and hibernate throws an exception:
Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
That's because Hibernate can't fetch multiple collections with one go. But if I change the List
to Set
and the LinkedList
to HashSet
this part works fine but the other - more annoying issue occurs.
When I am trying to get the entity from the database using:
entityManager.find(entityClass, primaryKey);
It fails with:
org.hibernate.AssertionFailure: null identifier
I am sure that ID I am passing to find
method is not null, I've debugged and I am sure of this. It somehow disappears inside Hibernate.
If I change collection types to LAZY
everything just works without errors but there are some circumstances where I need to use EAGER
.
Does anybody have a solution how to fix it? Either I could have a set but prevent assertion error from occurring or I could have a list but somehow avoid multiple fetch bags error.
I am using:
Hibernate 4.2.2.Final Tomcat 7 JPA 2.0 JDK 1.7
EDIT
I've just discovered that adding @Fetch(FetchMode.SELECT)
fixes the issue and I can use multiple list with EAGER
type, but is there anyway to solve this by not using Hibernate specific annotations? And why it fixed the issue in the first place?
EAGER fetching tells Hibernate to get the related entities with the initial query. This can be very efficient because all entities are fetched with only one query.
Both FetchType. LAZY and FetchType. EAGER are used to define the default fetch plan.
In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory. But when we enable lazy loading, if we pull up a UserLazy, OrderDetail data won't be initialized and loaded into a memory until we make an explicit call to it.
By default, the JPA @ManyToOne and @OneToOne annotations are fetched EAGERly, while the @OneToMany and @ManyToMany relationships are considered LAZY. This is the default strategy, and Hibernate doesn't magically optimize your object retrieval, it only does what is instructed to do.
The root cause of the problem is that when Hibernate fetches SQL query results there is no simple way to tell which child element belongs to which collection. See this blog entry for more detailed explanation with an example. To summarize you have following workarounds:
@Fetch(FetchMode.SELECT)
@IndexColumn(name="LIST_INDEX")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With