Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overcoming lazy loading issues in Hibernate, many-to-many, relationship

Tags:

java

hibernate

Teaching myself Hibernate, I have the following table structure/relationship

Relationship

Which is represented by the following classes...

Users

@Entity
@Table(name = "users")
public class User implements IUser<Role>, Serializable {

    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
    @SequenceGenerator(name = "user_key_seq")
    @Column(name = "key", insertable = false, updatable = false)
    private Long key;

    @Column(name = "name")
    private String name;

    @ManyToMany(cascade = {CascadeType.ALL})
    @JoinTable(name = "userroles",
                    joinColumns = {
                        @JoinColumn(name = "userkey")},
                    inverseJoinColumns = {
                        @JoinColumn(name = "rolekey")})
    private Set<Role> roles = new HashSet<>(5);

    @Override
    public Set<Role> getRoles() {
        return roles;
    }

    // Other setters and getters

}

Roles

@Entity
@Table(name = "roles")
public class Role implements IRole, Serializable {

    @Id
    @GeneratedValue(strategy = javax.persistence.GenerationType.IDENTITY)
    @SequenceGenerator(name = "roles_key_seq")
    @Column(name = "key", insertable = false, updatable = false)
    private Long key;

    @Column(name="name")
    private String name;

    @ManyToMany(cascade = {CascadeType.ALL})
    @JoinTable(name="parentroles",
                    joinColumns = {@JoinColumn(name="childkey")},
                    inverseJoinColumns = {@JoinColumn(name="parentkey")})
    private Set<Role> roles = new HashSet<>(5);

    // Other setters and getters

}

The problem I'm getting is this...

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.kaizen.chishiki.core.data.User.roles, could not initialize proxy - no Session
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
    at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:180)
    at og.kaizen.chishiki.core.testdatacore.Main.<init>(Main.java:37)
    at og.kaizen.chishiki.core.testdatacore.Main.main(Main.java:25)

Now, I know I could set the fetch type to FetchType.EAGER, but I'd prefer not to do that, apart from performance concerns, I'm trying to learn my way around these problems ;)

I was wondering if there was a way to write a Hibernate query to satisfy this relationship and load the rows manually (it would also allow me to return the interface of Role instead of the implementation as I'm having to do now (would allow me to maintain that contract)).

From what I've read, it would seem that I would need to construct an Entity for UserRoles. Not that I'm against this solution, but I was curious if there was a way to get around it.

roles appears in a number of other relationships, so there is no way it can form a direct relationship with the parent table (that is, I can't put the key of the parent table in the role table directly, besides, users can have multiple roles)

The other solution I had in mind was to write a stored procedure to do it for me. While this is viable solution that I'm not above doing, it does make migrating the application to another database more difficult, not a show stopper, but I'm trying to keep these ideas in mind.

like image 907
MadProgrammer Avatar asked Jul 09 '14 21:07

MadProgrammer


1 Answers

If you want to load users with their roles, but still keep the association lazy, use a HQL query containing a left join fetch:

select u from User u left join fetch u.roles where ...

If you have a User and want to make sure its roles collection is initialized before closing the session, call Hibernate.initialize(user.getRoles()).

like image 197
JB Nizet Avatar answered Oct 23 '22 06:10

JB Nizet