Grails

Cannot get ID of lazy loaded single-ended association without proxy initialization and SELECT

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 1.0.2
  • Component/s: None
  • Labels:
    None

Description

Given a class like:

class UserIdentifier {
static belongsTo = [user:User]
static mapping = { user lazy:true }

//...
}

Given a loaded UserIdentifier, I want to be able to get the ID of the "user" without Hibernate doing a select. I do this regularly in pure Java and it is a documented feature in Hibernate (see http://www.hibernate.org/118.html#A21). In Java you can do userIdentifier.getUser().getId() and the full proxy will not be initialized and no select will happen. It makes sense because the User ID is in the UserIdentifier table due to the belongsTo. In Grails, as soon as you do a userIdentifier.getUser() it does a select of the associated user.

Activity

Hide
Graeme Rocher added a comment -

The nature of the groovy runtime is that is triggers the initialization of the object when the metaclass is accessed for some reason. I'm not sure if this is fixable from a Groovy perspective. What I have done though is add a new meta-property that by convention ends in "Id" so you can do

def id = userIdentifier.userId

And it won't initialise the lazy proxy

Show
Graeme Rocher added a comment - The nature of the groovy runtime is that is triggers the initialization of the object when the metaclass is accessed for some reason. I'm not sure if this is fixable from a Groovy perspective. What I have done though is add a new meta-property that by convention ends in "Id" so you can do
def id = userIdentifier.userId
And it won't initialise the lazy proxy
Hide
Bob Tiernay added a comment -

This seems to return null in the case where the base object is not yet saved, but associations are set.

params['to.id'] = params.id
params['from.id'] = session.member.id
def feedback = new Feedback(params)
println feedback.fromId // prints null, but should print id
println feedback.from.id // prints actual value, as expected

I've tried step debugging through this issue and I'm seeing that a NoSuchMethodException is being thrown in

GrailsDomainConfigurationUtil.getAssociationIdentifier

public static Serializable getAssociationIdentifier(Object target, String propertyName, GrailsDomainClass referencedDomainClass) {
        String getterName = GrailsClassUtils.getGetterName(propertyName);

        try {
            Method m = target.getClass().getDeclaredMethod(getterName, EMPTY_CLASS_ARRAY);
            Object value = m.invoke(target, null);
            if(value != null && referencedDomainClass != null) {
                String identifierGetter = GrailsClassUtils.getGetterName(referencedDomainClass.getIdentifier().getName());
                m = value.getClass().getDeclaredMethod(identifierGetter, EMPTY_CLASS_ARRAY);
                return (Serializable)m.invoke(value, null);
            }
        } catch (NoSuchMethodException e) {
           // ignore
        } catch (IllegalAccessException e) {
           // ignore
        } catch (InvocationTargetException e) {
            // ignore
        }
        return null;
    }

I'm thinking this could be caused by the use of the constructor over a hibernate proxy as loaded from a Feedback.get(id) call.

At any rate, I've had to use the second form for now (feedback.from.id), although in this case I could have got a way with just using the parameter.

Show
Bob Tiernay added a comment - This seems to return null in the case where the base object is not yet saved, but associations are set.
params['to.id'] = params.id
params['from.id'] = session.member.id
def feedback = new Feedback(params)
println feedback.fromId // prints null, but should print id
println feedback.from.id // prints actual value, as expected
I've tried step debugging through this issue and I'm seeing that a NoSuchMethodException is being thrown in GrailsDomainConfigurationUtil.getAssociationIdentifier
public static Serializable getAssociationIdentifier(Object target, String propertyName, GrailsDomainClass referencedDomainClass) {
        String getterName = GrailsClassUtils.getGetterName(propertyName);

        try {
            Method m = target.getClass().getDeclaredMethod(getterName, EMPTY_CLASS_ARRAY);
            Object value = m.invoke(target, null);
            if(value != null && referencedDomainClass != null) {
                String identifierGetter = GrailsClassUtils.getGetterName(referencedDomainClass.getIdentifier().getName());
                m = value.getClass().getDeclaredMethod(identifierGetter, EMPTY_CLASS_ARRAY);
                return (Serializable)m.invoke(value, null);
            }
        } catch (NoSuchMethodException e) {
           // ignore
        } catch (IllegalAccessException e) {
           // ignore
        } catch (InvocationTargetException e) {
            // ignore
        }
        return null;
    }
I'm thinking this could be caused by the use of the constructor over a hibernate proxy as loaded from a Feedback.get(id) call. At any rate, I've had to use the second form for now (feedback.from.id), although in this case I could have got a way with just using the parameter.
Hide
Graeme Rocher added a comment -

Bulk closing bunch of resolved issues

Show
Graeme Rocher added a comment - Bulk closing bunch of resolved issues

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: