Search code examples
grailsgrails-orm

failed to lazily initialize a collection of role: website.User.purchasedProducts, could not initialize proxy - no Session


I'm trying to setup a tag lib to check if a user purchased a product. However, when my taglib is run, I get this error:

ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[grailsDispatcherServlet] - Servlet.service() for servlet [grailsDispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.grails.gsp.GroovyPagesException: Error processing GroovyPageView: [views/derbypro/index.gsp:124] Error executing tag <g:ifPurchased>: failed to lazily initialize a collection of role: website.User.purchasedProducts, could not initialize proxy - no Session] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: website.User.purchasedProducts, could not initialize proxy - no Session

Here is my tag lib:

package website

class PurchasedProductTagLib {
    def ifPurchased = { attrs, body ->
        if (!session.user) return

        if (Product.findById(attrs.product) in session.user.purchasedProducts) { // <-- error here
            out << body()
        }
    }

    def ifNotPurchased = { attrs, body ->
        if (!(Product.findById(attrs.product) in session.user?.purchasedProducts)) {
            out << body()
        }
    }
}

And here is my User domain class:

package website

import org.mindrot.jbcrypt.BCrypt

class User {
    String username
    String passwordHash
    String email

    static hasMany = [purchasedProducts: Product]

    User(String username, String password, String email) {
        this.username = username;
        passwordHash = BCrypt.hashpw(password, BCrypt.gensalt())
        this.email = email
    }
}

This only seems to be happening after logging in, if the user registers instead (and is redirected back to this page), this error does not happen.

I have my tag libs nested inside one-another, if that does anything.


Solution

  • Well! As logs say that No session. You are using an object which is in detached state. Hence, either attach the object back or just fetch the object by id.

    if(!session.user.isAttached()){
         session.user.attach();
    }
    

    Or

    Long id = session.user.id.toLong();
    User user = User.get(id);
    

    Both the way you will attach the object to a session.

    Edit

    Another solution could be to eager load the hasMany part. But I would not prefer this solution as it will slow down my domain fetch. Also, it would fetch hasMany data that might not be required in all places.