In Hibernate, @ManyToOne
relationship hardly results any problem since default fetch type is EAGER
.
However, we encounter critical problems at the @OnetoMany
end. As we attempt to fetch a collection,
LazyInitializationException: could not initialize proxy
is thrown since the default fetch type is LAZY
for one-to-many.
In such case, we shall either set:
@LazyCollection(LazyCollectionOption.FALSE)
, which although it resolves the problem, it hits the performance significantly when there are bunch of records.fetch
mode: left join but it throwsorg.hibernate.HibernateException: cannot simultaneously fetch multiple bags
According to my knowledge, Hibernate suggests couple of mechanisms to overcome this issue:
Option 1:
Specifying
@IndexColumn
instead of makingLazyCollectionOption.FALSE
. As a consequnce, the following behaviors are identified which also impacts on the performance:A temporary table is created with primary keys of respective entities (
@OnetoMany
). So when there are many one-to-many relationships, temporary table is created for each.
Option 2:
Changing data type of collection from
List
toSet
. This is leads to a problematic situation at the front-end with Struts 2 becauseSet
is index based collection as we need to add records dynamically in an iterative manner.In order to overcome this issue, we shall make use of DTOs to capture UI inputs. By making collection type
List
in DTO andSet
in domain, and by having assembler we shall do the required conversion fromList
→Set
(DTO → Domain), and vice versa.
Is the resolution mentioned under Option 2 a viable solution? If not, please provide suggestions and feedback.
In my experience, you usually have only one or two places where you need eager initialization (example: in a "record details" view). For such situations, where lazy will be always the case, except for a couple of places where eager is needed, there's a Hibernate feature called "Fetch profile". It's a relatively new feature, not very known, but it's very powerful and can probably help in this case.
Unfortunately, this is not in JPA yet, which means that you'll need to add a bit of proprietary Hibernate parts in your otherwise clean JPA code, but it's a low price to pay, IMO.