Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly map collection of enums in hibernate?

I have an entity which references a list of type enum. The list is stored in the database as following:

userName    role
-----------------------
user0001    role1
user0001    role2
user0001    role3
user0002    role1

The corresponding java class is roughly like this:

@Entity
@Table(name = "UserTable")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "userId")
    private Integer id;
    @Column(name = "user_name")
    private String userName;

    @ElementCollection(targetClass = Role.class)
    @CollectionTable(name = "User_Roles")
    @Column(name = "role")
    @Enumerated(EnumType.STRING)
    private List<Role> roles;

}

I checked this and this question for the mapping. Yet I have two issues. First issue is that the userName is not the PK in my UserTable and as far as I know, hibernate does join on the PK.

The second issue is this error with the current setup:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.project.Common.User.roles, could not initialize proxy - no Session

This error shall be fixed by EAGER loading, but as I tried that one, I got the following error at startup:

java.lang.IllegalStateException: Attempt to register multiple SQL table aliases [roles1_, roles2_, etc] against query space uid [< gen:1>]

What do I need to change in order for this mapping to work?


Please note that I wouldn't like to perform any database changes if that is in any way possible.

Also I do think that I would actually have to go with FetchType.EAGER, as I for now only query the database once and would need to get roles as well for later usage. Of course I could also change the way my application handles this and query the roles again when I need them explicitly, tho I am not sure if that way would be better.

like image 905
XtremeBaumer Avatar asked Jan 10 '19 10:01

XtremeBaumer


1 Answers

Alright, I found a not so nice workaround. First of all, I annotated the List<Role> roles; as following:

@ElementCollection(targetClass = Role.class)
@JoinTable(name = "User_Roles", joinColumns = @JoinColumn(name = "userName"))
@Enumerated(EnumType.STRING)
@Column(name = "role")
private List<Role> roles;

My Role enum does not have any annotations.

This setup would normally result in the LazyInitializationException, which I worked around by adding a System.out.println(user); as this does access the roles list (replacing it with a getRoles() resulted in the same exception) directly after fetching the user.

As you can guess, this solution is not really fine/acceptible at all. As long as I don't find a better solution (most probably eager-loading), I will roll with this one.


UPDATE

I actually got it solved. It works now with eager-loading. In fact, the setup remained as posted above in the answer. The IllegalStateException I mentioned in the question, is actually caused by the bug HHH-12594. I simply removed hibernate.default_batch_fetch_size from my configuration and it then worked as intended.

like image 96
XtremeBaumer Avatar answered Oct 24 '22 18:10

XtremeBaumer