I am facing issues while retrieving data for entities having bi-directional many-to-many relationship. If I use List
for storing entities, I get unable to fetch multiple bags simultaneously error. If i change my code to use Set
, I get stackoverflow error.
Details :
User has Many Bank Accounts; Bank Account can have many users
User.java
@ManyToMany(fetch = FetchType.EAGER, mappedBy="user")
private List<BankAccount> bankAccounts = new ArrayList<BankAccount>();
BankAccount.java
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_bankaccount",
joinColumns = @JoinColumn(name="bank_account_id"),
inverseJoinColumns = @JoinColumn(name = "user_id")
)
private List<User> user = new ArrayList<User>();
DB Tables
Users
user_id PK
Bankaccount
bank_account_id PK
user_bankaccount
bank_account_id PK ( references bankaccount.bank_account_id )
user_id PK ( references user.user_id )
issues
getAllUsers
) using a JUnit test case, I get unable to fetch multiple bags simultaneously error.Set
and HashSet
instead of List and ArrayList
respectively, I get stackoverflow error.Please help me and let me know if code is wrong or its a known hibernate issue with specific version of libs that I am using.
I've faced the similar issue and the root cause is a Lombok generation code as Vjeetje mentioned above. My code uses the annotation @Data, which generates hashCode and ToString methods with cross-dependent fields and this structure leads to Hibernate stuck. So, one should care to avoid these infinite loop calls, in my case I just added the exclusion parameters, like @EqualsAndHashCode(exclude="dependent_list") and @ToString(exclude = "dependent_list"). It solves stack overflow issue.
You cannot map the many to many relationship on both of the lists, hibernate will then try to fetch a collection for every nested element i.e. every user in the users list has a list of bank accounts which have a list of users... . think of it of a never ending recursion.
(Let's leave the fetch
attribute aside for now). Your mapping is perfectly valid and is the right way to map a bidirectional many-to-many relationship. From the JPA 2.0 specification:
2.10.4 Bidirectional ManyToMany Relationships
...
Example:
@Entity public class Project { private Collection<Employee> employees; @ManyToMany public Collection<Employee> getEmployees() { return employees; } public void setEmployees(Collection<Employee> employees) { this.employees = employees; } ... } @Entity public class Employee { private Collection<Project> projects; @ManyToMany(mappedBy="employees") public Collection<Project> getProjects() { return projects; } public void setProjects(Collection<Project> projects) { this.projects = projects; } ... }
In this example:
- Entity
Project
references a collection of EntityEmployee
.- Entity
Employee
references a collection of EntityProject
.- Entity
Project
is the owner of the relationship....
That being said, I'm unsure of the behavior when using EAGER
fetching on both sides (will it lead to an infinite cycle?), the JPA specification is pretty blurry about this and I can't find any clear mention that it is forbidden. But I bet that it's part of the problem.
But in the particular case of Hibernate, I'd expect Hibernate to be able to handle cycles as mentioned in this comment from Emmanuel Bernard:
LAZY or EAGER should be orthogonal to an infinite loop issue in the codebase. Hibernate knows how to handle cyclic graphs
Funnily enough, I've answered a very similar question recently (very close problem). Maybe an hint that something is wrong in Hibernate (my understanding of the above comment is that using EAGER fetching on both sides should work).
I'll thus conclude my answer in the same way: if you can provide a test case allowing to reproduce the problem, open a Jira issue.
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