validate lazy association only if its loaded

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

validate lazy association only if its loaded

basejump (Josh)
I am trying to save a domain without loading the lazy associations  

class Face {
    Nose nose
    String description
}
class Nose {
    static belongsTo = [face:Face]
}

...
def face = Face.load(1)
face.description = "pretty"
face.save()

this will force the proxied nose to hit the database and load. This is what I am trying to avoid as its slowing our updates down considerably as we have some domains with quite a few associations.
deepValidate:false works to prevent the db hit but then I loose validation when it has actually been loaded and changed.

The question: Is there a way to tell gorm "don't load the nose association if its a lazy proxy and only validate/save the nose if its been loaded"


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: validate lazy association only if its loaded

longwa
We are having the same problem. In general, it seems like deepValidation is a big hit on performance, particularly for a large interconnected object graph. One thing we did was setup a few of the problematic associations to be fetch: 'join' in the mappings. That at least does a single query to load both the Face and Nose in your example.

The worst thing about this example is that you will actually end up fetching the Face twice, and the Nose once. The call to "face.description" will unwrap the Face for query one, then the deep validate fetches the Nose (even though it's not dirty, not fetched, not anything), then to add insult to injury, the validation for the Nose will fetch the Face again using the nose_id foreign key.

I just can't ever convince myself that this behavior is correct or desirable.

Unfortunately, I've never seen a way to do what you want. Maybe if you could determine if the Nose association was loaded, you could pass that to the deepValidation: flag..something like:

save(deepValidate: isLoaded(face.nose))

I just don't know how to implement the isLoaded() in this case....

-Aaron


On Sat, Jun 16, 2012 at 2:49 AM, Josh (basejump) <[hidden email]> wrote:
I am trying to save a domain without loading the lazy associations

class Face {
   Nose nose
   String description
}
class Nose {
   static belongsTo = [face:Face]
}

...
def face = Face.load(1)
face.description = "pretty"
face.save()

this will force the proxied nose to hit the database and load. This is what I am trying to avoid as its slowing our updates down considerably as we have some domains with quite a few associations.
deepValidate:false works to prevent the db hit but then I loose validation when it has actually been loaded and changed.

The question: Is there a way to tell gorm "don't load the nose association if its a lazy proxy and only validate/save the nose if its been loaded"


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: validate lazy association only if its loaded

basejump (Josh)
I'm digging further to see if I could check if nose is a proxy and I have more questions on whats happening internally and it if its expected.
using the following example

def face = Face.get(1)
//this will not hit the database
assert face.noseId
assert !GrailsHibernateUtil.isInitialized(face,'nose')
//this hits the database? should it? I thought it only happened on property access.
assert face.nose
//this of course now returns true
assert GrailsHibernateUtil.isInitialized(h,'flex')

?? should just accessing face.nose hit the database to load the nose?


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: validate lazy association only if its loaded

longwa
Yeah, I see that same behavior in our application.

My understanding from reading the docs is that calling "face.nose" should NOT hit the database. In fact, calling "face.nose.id" should not hit the database either. We rely on the fact that accessing the "id" property for to-one associations should not cause a database load and are seeing a lot of cases where this isn't true. In particular, it's annoying when you get a LazyInitializationException as a result, since it shouldn't even be initializing!

I'm not convinced this is working as advertised.

-Aaron

On Sat, Jun 16, 2012 at 1:47 PM, Josh (basejump) <[hidden email]> wrote:
I'm digging further to see if I could check if nose is a proxy and I have more questions on whats happening internally and it if its expected.
using the following example

def face = Face.get(1)
//this will not hit the database
assert face.noseId
assert !GrailsHibernateUtil.isInitialized(face,'nose')
//this hits the database? should it? I thought it only happened on property access.
assert face.nose
//this of course now returns true
assert GrailsHibernateUtil.isInitialized(h,'flex')

?? should just accessing face.nose hit the database to load the nose?


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email



Reply | Threaded
Open this post in threaded view
|

Re: validate lazy association only if its loaded

basejump (Josh)
In reply to this post by longwa
This is a particularly nasty issue for us as we are sometimes spinning through a 200,000 items and making modifications. Have you logged any jiras?

On Jun 16, 2012, at 10:18 AM, Aaron Long wrote:

> We are having the same problem. In general, it seems like deepValidation is a big hit on performance, particularly for a large interconnected object graph. One thing we did was setup a few of the problematic associations to be fetch: 'join' in the mappings. That at least does a single query to load both the Face and Nose in your example.
Yes that does help if we know its being edited but much of the time we can't predict that.
>
> The worst thing about this example is that you will actually end up fetching the Face twice, and the Nose once. The call to "face.description" will unwrap the Face for query one, then the deep validate fetches the Nose (even though it's not dirty, not fetched, not anything), then to add insult to injury, the validation for the Nose will fetch the Face again using the nose_id foreign key.
I see this too. Ideally this is not to awful as the database has it cached but I don't think it should even be looking at the db. This may be a hibernate issue.
>
> I just can't ever convince myself that this behavior is correct or desirable.
I can't see how this is expected functionality but perhaps there was some underlying reason for this and perhaps some of it results from hibernate black magic.
I'm trying to find the relevant chunks of grails code that is involved in the saving and loading of associations to see whats going on.
>
> Unfortunately, I've never seen a way to do what you want. Maybe if you could determine if the Nose association was loaded, you could pass that to the deepValidation: flag..something like:
>
> save(deepValidate: isLoaded(face.nose))
>
> I just don't know how to implement the isLoaded() in this case....
That exactly where I was going with the example I sent using GrailsHibernateUtil.isInitialized , If I come up with a working solution I will post it.
>
> -Aaron


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email