6

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.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • possible duplicate of [hibernate: LazyInitializationException: could not initialize proxy](http://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy) – Zeus Jul 09 '14 at 21:57
  • I'm not sure if you can retrieve it as an instance of the interface rather than a class. – Luiggi Mendoza Jul 09 '14 at 21:59
  • @LuiggiMendoza What I want to do is return a `Set` of the interface, containing the implementations, the reason I'm trying to do this, is I have a interface layer above this that my program talks to, so that the actual mechanisms by which the data is loaded is hidden from the program layer, so if I wanted to change the "data layer" I could, that's all ;) – MadProgrammer Jul 09 '14 at 22:18
  • @Zeus Yes, I've read that, as I stated, I know I can change the `fetch` type, but I'd prefer not to do that if I can help it and I would like to know alternative solutions to this particular problem. This is just a simple example, I have more complex relationships which might end up loading 100's if not more child records ;) – MadProgrammer Jul 09 '14 at 22:24

3 Answers3

4

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()).

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • How do I define the constraint/relationship between the roles and the users or doesn't it matter or is defined already by the annotations? – MadProgrammer Jul 10 '14 at 00:14
  • The association you have defined is OK. You may define an inverse association (i.e role.users), but I guess it won't really be useful. It's not to execute the above query at least. – JB Nizet Jul 10 '14 at 05:49
  • Okay, how would you accomplish this after the `Session` has been closed? – MadProgrammer Jul 10 '14 at 07:06
  • You can't. That's how lazy fetching works: it needs a session open to be able to execute the SQL query needed to populate the association. If the roles must be fetched when fetching a user, then the transaction used to fetch the user must also fetch the roles. – JB Nizet Jul 10 '14 at 07:08
  • Okay, this has given me some ideas and I've been able to hobble something together for the mean time. Cheers – MadProgrammer Jul 10 '14 at 07:32
1

If you are using Hibernate 4.1.6+ then one can handle those lazy association problems by using hibernate.enable_lazy_load_no_trans property in hibernate.properties.

For More refer : https://stackoverflow.com/a/11913404/286588

Community
  • 1
  • 1
Farm
  • 3,356
  • 2
  • 31
  • 32
  • Using this doesn't really solve the problem and can potentially cause more problems later on as this can lead to Hibernate loading a huge amount of data for one simple item. And this is why lazy loading exists. – Martin Mar 26 '15 at 14:49
0

I solved this problem by annotating the method in the controller as transactional.As lazy-load basically returns a list of future objects ,the method needs to be transactional.