I ran into a bit of a weird scenario recently with grails. I have a couple of classes similar to those below:
Essentially, I have a many to one relationship. Now, consider the following code:
Assuming that there is actually a bar set on this particular foo, what will you get?
You’ll get the actual Bar, completely instantiated. Now, imagine the exact same scenario in normal java with the exact same equivalent hibernate settings via annotations. (I’m too lazy to model what that would look like) What would you get back for a similar call? You would get back a proxy! Then, if you called something on the proxy, hibernate would go and fetch the actual object for you.
Gorm unwraps the proxy when the object itself is called via a property.
If you take a look at the HibernatePluginSupport class, which configures all of the dynamic Gorm methods (and the first place I go when I want to see how a particular method is actually working) you will see this in action:
What whoever wrote this is trying to avoid is the ‘proxy hell’ mentioned in the comment. The hibernate docs have a good explanation of it:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-fetching-lazy
As does the Grails docs:
http://grails.org/doc/latest/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.5.2.8%20Eager%20and%20Lazy%20Fetching
They’re more eagerly fetching the lazy relationships than Hibernate does to avoid some of the instanceof check issues outlined in the above links.
Now, back to my issue. What happens if you want to obtain the identifier of your relationship without actually resulting in a database call to get it? The proxy has the identifier already, that’s how it loads it up when you call it. In pure hibernate there’s a few ways to do it:
I didn’t find this out until I had wasted quite a few hours, but apparently this was a known issue: http://jira.grails.org/browse/GRAILS-2570 I never saw this when googling for it originally, but you can essentially say:
And you will get the id of the bar without the proxy being unwrapped. I’m not sure this is referenced anywhere in the docs though.
class Foo {
Bar bar
}
class Bar {
static hasMany = [foos: Foo]
}
Essentially, I have a many to one relationship. Now, consider the following code:
Foo foo = Foo.get(1)
Bar bar = foo.bar
Assuming that there is actually a bar set on this particular foo, what will you get?
You’ll get the actual Bar, completely instantiated. Now, imagine the exact same scenario in normal java with the exact same equivalent hibernate settings via annotations. (I’m too lazy to model what that would look like) What would you get back for a similar call? You would get back a proxy! Then, if you called something on the proxy, hibernate would go and fetch the actual object for you.
Gorm unwraps the proxy when the object itself is called via a property.
If you take a look at the HibernatePluginSupport class, which configures all of the dynamic Gorm methods (and the first place I go when I want to see how a particular method is actually working) you will see this in action:
static final LAZY_PROPERTY_HANDLER = { String propertyName ->So, anytime you access your properties, the above code is going to unwrap it.
def propertyValue = PropertyUtils.getProperty(delegate, propertyName)
if (propertyValue instanceof HibernateProxy) {
return GrailsHibernateUtil.unwrapProxy(propertyValue)
}
return propertyValue
}
/**
* This method overrides a getter on a property that is a Hibernate proxy
* in order to make sure the initialized object is returned hence avoiding
* Hibernate proxy hell
*/
static void handleLazyProxy(GrailsDomainClass domainClass,
GrailsDomainClassProperty property) {
String propertyName = property.name
def getterName = GrailsClassUtils.getGetterName(propertyName)
def setterName = GrailsClassUtils.getSetterName(propertyName)
domainClass.metaClass."${getterName}" =
LAZY_PROPERTY_HANDLER.curry(propertyName)
domainClass.metaClass."${setterName}" = {
PropertyUtils.setProperty(delegate, propertyName, it)
}
for (GrailsDomainClass sub in domainClass.subClasses) {
handleLazyProxy(sub, sub.getPropertyByName(property.name))
}
}
What whoever wrote this is trying to avoid is the ‘proxy hell’ mentioned in the comment. The hibernate docs have a good explanation of it:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-fetching-lazy
As does the Grails docs:
http://grails.org/doc/latest/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html#5.5.2.8%20Eager%20and%20Lazy%20Fetching
They’re more eagerly fetching the lazy relationships than Hibernate does to avoid some of the instanceof check issues outlined in the above links.
Now, back to my issue. What happens if you want to obtain the identifier of your relationship without actually resulting in a database call to get it? The proxy has the identifier already, that’s how it loads it up when you call it. In pure hibernate there’s a few ways to do it:
- Session.getIdentifier
- entity.getId() (assuming you are using property based configuration)
- Cast it to a HibernateProxy, get the LazyLoadInitializer and get the Identifier from it
I didn’t find this out until I had wasted quite a few hours, but apparently this was a known issue: http://jira.grails.org/browse/GRAILS-2570 I never saw this when googling for it originally, but you can essentially say:
foo.barId
And you will get the id of the bar without the proxy being unwrapped. I’m not sure this is referenced anywhere in the docs though.
Comments
Thanks for putting this information out there, you saved me a few hours of frustration!
Great post, thanks! Already bookmarked this for future reference!
Thanks for posting this!