Quantcast

options for lazy-loading one-to-one

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

options for lazy-loading one-to-one

Alan Bowsher-2
I've seen this JIRA issue:  http://jira.grails.org/browse/GRAILS-5077

I'm assuming you still can't have a lazy-loaded hasOne relationship.  With that in mind, I'm wondering what my options are.

Here's the situation:  

class Parent {
    static hasOne = [child: Child]
}

class Child {
    static belongsTo = [parent:  Parent]

   static mapping = {
        tablePerHierarchy(false)
    }
}

class Child1 extends Child {}
class Child2 extends Child {}

In our case, we have many children classes.  When the Parent is retrieved, this results in an outer join against every single ChildX table.  That's ok most of the time, but not in batch operations.  So we want to avoid that.  (we cannot easily change this design because the system has to be flexible in adding new Child types, and we don't want a single table with hundreds of columns)

Options:

1) Drop down to Hibernate mapping level?  I'm guessing from the JIRA comments this doesn't work, just checking...
2) Don't use hasOne to model the relationship?  It seems not using this for other one-to-ones we have allows them to be lazy.
3) Use straight SQL to get the Parent (using this now)
4) Query from the child up where we are able?

I tried Option 4 by querying against a specific Child, but when you get to the Parent, GORM turns around and gets the Child again even though you've already got it, so we get all those outer joins again.  Is there any way to convince GORM not to do this when I've already got the Child, such as a join fetch of the parent when getting the Child?

i.e.
Child1.get(id) // Get the parent here also so GORM sees we've already got the child and doesn't turn back around and try to get it

Thanks...
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: options for lazy-loading one-to-one

Alan Bowsher-2
Fwiw, I tried a couple of different things here.

1) If you don't use hasOne, and get the key in the parent table instead of the child table, then you do get a lazy-loaded one-to-one.  However, when you get the child, if you still use a belongsTo to get back to the parent, you'll get an extra query back to the parent table.

2) If you model it as a oneToMany/belongsTo relationship and use a setter/getter to fake out the relationship to look like a one-to-one, as far as I can tell, you can achieve the same behavior (same queries, save/validation cascading, etc.) and table structure as a hasOne/belongsTo, but get the desired lazy loading.

So the Parent below would look something like:

class Parent {
    static hasMany = [children: Child]
    static transients = ['child']

    public void setChild(ChildBase child) {

        // TODO add some checking here or simply replace any child already in the set, we only want one in the set.
        addToChildren(child)
    }

    public ChildBase getChild() {
        return children?.iterator()?.next()
    }
}

On Fri, Jul 20, 2012 at 10:45 AM, Alan Bowsher <[hidden email]> wrote:
I've seen this JIRA issue:  http://jira.grails.org/browse/GRAILS-5077

I'm assuming you still can't have a lazy-loaded hasOne relationship.  With that in mind, I'm wondering what my options are.

Here's the situation:  

class Parent {
    static hasOne = [child: Child]
}

class Child {
    static belongsTo = [parent:  Parent]

   static mapping = {
        tablePerHierarchy(false)
    }
}

class Child1 extends Child {}
class Child2 extends Child {}

In our case, we have many children classes.  When the Parent is retrieved, this results in an outer join against every single ChildX table.  That's ok most of the time, but not in batch operations.  So we want to avoid that.  (we cannot easily change this design because the system has to be flexible in adding new Child types, and we don't want a single table with hundreds of columns)

Options:

1) Drop down to Hibernate mapping level?  I'm guessing from the JIRA comments this doesn't work, just checking...
2) Don't use hasOne to model the relationship?  It seems not using this for other one-to-ones we have allows them to be lazy.
3) Use straight SQL to get the Parent (using this now)
4) Query from the child up where we are able?

I tried Option 4 by querying against a specific Child, but when you get to the Parent, GORM turns around and gets the Child again even though you've already got it, so we get all those outer joins again.  Is there any way to convince GORM not to do this when I've already got the Child, such as a join fetch of the parent when getting the Child?

i.e.
Child1.get(id) // Get the parent here also so GORM sees we've already got the child and doesn't turn back around and try to get it

Thanks...

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: options for lazy-loading one-to-one

Alan Bowsher-2
Well, mapping it as a collection behind the scenes breaks a lot of our code, probably due to the way Hibernate treats collections differently in the session... lots of issues with 'dirty collections', 'attempt to associate a collection with two open sessions', etc. that we didn't have before with a true one-to-one.

This is bad for us from a performance perspective.

On Mon, Jul 23, 2012 at 5:45 PM, Alan Bowsher <[hidden email]> wrote:
Fwiw, I tried a couple of different things here.

1) If you don't use hasOne, and get the key in the parent table instead of the child table, then you do get a lazy-loaded one-to-one.  However, when you get the child, if you still use a belongsTo to get back to the parent, you'll get an extra query back to the parent table.

2) If you model it as a oneToMany/belongsTo relationship and use a setter/getter to fake out the relationship to look like a one-to-one, as far as I can tell, you can achieve the same behavior (same queries, save/validation cascading, etc.) and table structure as a hasOne/belongsTo, but get the desired lazy loading.

So the Parent below would look something like:

class Parent {
    static hasMany = [children: Child]
    static transients = ['child']

    public void setChild(ChildBase child) {

        // TODO add some checking here or simply replace any child already in the set, we only want one in the set.
        addToChildren(child)
    }

    public ChildBase getChild() {
        return children?.iterator()?.next()
    }
}

On Fri, Jul 20, 2012 at 10:45 AM, Alan Bowsher <[hidden email]> wrote:
I've seen this JIRA issue:  http://jira.grails.org/browse/GRAILS-5077

I'm assuming you still can't have a lazy-loaded hasOne relationship.  With that in mind, I'm wondering what my options are.

Here's the situation:  

class Parent {
    static hasOne = [child: Child]
}

class Child {
    static belongsTo = [parent:  Parent]

   static mapping = {
        tablePerHierarchy(false)
    }
}

class Child1 extends Child {}
class Child2 extends Child {}

In our case, we have many children classes.  When the Parent is retrieved, this results in an outer join against every single ChildX table.  That's ok most of the time, but not in batch operations.  So we want to avoid that.  (we cannot easily change this design because the system has to be flexible in adding new Child types, and we don't want a single table with hundreds of columns)

Options:

1) Drop down to Hibernate mapping level?  I'm guessing from the JIRA comments this doesn't work, just checking...
2) Don't use hasOne to model the relationship?  It seems not using this for other one-to-ones we have allows them to be lazy.
3) Use straight SQL to get the Parent (using this now)
4) Query from the child up where we are able?

I tried Option 4 by querying against a specific Child, but when you get to the Parent, GORM turns around and gets the Child again even though you've already got it, so we get all those outer joins again.  Is there any way to convince GORM not to do this when I've already got the Child, such as a join fetch of the parent when getting the Child?

i.e.
Child1.get(id) // Get the parent here also so GORM sees we've already got the child and doesn't turn back around and try to get it

Thanks...


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: options for lazy-loading one-to-one

basejump (Josh)
try this
http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html
On Jul 24, 2012, at 11:12 AM, Alan Bowsher wrote:

Well, mapping it as a collection behind the scenes breaks a lot of our code, probably due to the way Hibernate treats collections differently in the session... lots of issues with 'dirty collections', 'attempt to associate a collection with two open sessions', etc. that we didn't have before with a true one-to-one.

This is bad for us from a performance perspective.

On Mon, Jul 23, 2012 at 5:45 PM, Alan Bowsher <[hidden email]> wrote:
Fwiw, I tried a couple of different things here.

1) If you don't use hasOne, and get the key in the parent table instead of the child table, then you do get a lazy-loaded one-to-one.  However, when you get the child, if you still use a belongsTo to get back to the parent, you'll get an extra query back to the parent table.

2) If you model it as a oneToMany/belongsTo relationship and use a setter/getter to fake out the relationship to look like a one-to-one, as far as I can tell, you can achieve the same behavior (same queries, save/validation cascading, etc.) and table structure as a hasOne/belongsTo, but get the desired lazy loading.

So the Parent below would look something like:

class Parent {
    static hasMany = [children: Child]
    static transients = ['child']

    public void setChild(ChildBase child) {

        // TODO add some checking here or simply replace any child already in the set, we only want one in the set.
        addToChildren(child)
    }

    public ChildBase getChild() {
        return children?.iterator()?.next()
    }
}

On Fri, Jul 20, 2012 at 10:45 AM, Alan Bowsher <[hidden email]> wrote:
I've seen this JIRA issue:  http://jira.grails.org/browse/GRAILS-5077

I'm assuming you still can't have a lazy-loaded hasOne relationship.  With that in mind, I'm wondering what my options are.

Here's the situation:  

class Parent {
    static hasOne = [child: Child]
}

class Child {
    static belongsTo = [parent:  Parent]

   static mapping = {
        tablePerHierarchy(false)
    }
}

class Child1 extends Child {}
class Child2 extends Child {}

In our case, we have many children classes.  When the Parent is retrieved, this results in an outer join against every single ChildX table.  That's ok most of the time, but not in batch operations.  So we want to avoid that.  (we cannot easily change this design because the system has to be flexible in adding new Child types, and we don't want a single table with hundreds of columns)

Options:

1) Drop down to Hibernate mapping level?  I'm guessing from the JIRA comments this doesn't work, just checking...
2) Don't use hasOne to model the relationship?  It seems not using this for other one-to-ones we have allows them to be lazy.
3) Use straight SQL to get the Parent (using this now)
4) Query from the child up where we are able?

I tried Option 4 by querying against a specific Child, but when you get to the Parent, GORM turns around and gets the Child again even though you've already got it, so we get all those outer joins again.  Is there any way to convince GORM not to do this when I've already got the Child, such as a join fetch of the parent when getting the Child?

i.e.
Child1.get(id) // Get the parent here also so GORM sees we've already got the child and doesn't turn back around and try to get it

Thanks...



Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: options for lazy-loading one-to-one

Alan Bowsher-2
Thanks for the tip!  I'll have to check that out...

On Wed, Aug 8, 2012 at 11:03 PM, Josh (basejump) <[hidden email]> wrote:
try this
http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html

On Jul 24, 2012, at 11:12 AM, Alan Bowsher wrote:

Well, mapping it as a collection behind the scenes breaks a lot of our code, probably due to the way Hibernate treats collections differently in the session... lots of issues with 'dirty collections', 'attempt to associate a collection with two open sessions', etc. that we didn't have before with a true one-to-one.

This is bad for us from a performance perspective.

On Mon, Jul 23, 2012 at 5:45 PM, Alan Bowsher <[hidden email]> wrote:
Fwiw, I tried a couple of different things here.

1) If you don't use hasOne, and get the key in the parent table instead of the child table, then you do get a lazy-loaded one-to-one.  However, when you get the child, if you still use a belongsTo to get back to the parent, you'll get an extra query back to the parent table.

2) If you model it as a oneToMany/belongsTo relationship and use a setter/getter to fake out the relationship to look like a one-to-one, as far as I can tell, you can achieve the same behavior (same queries, save/validation cascading, etc.) and table structure as a hasOne/belongsTo, but get the desired lazy loading.

So the Parent below would look something like:

class Parent {
    static hasMany = [children: Child]
    static transients = ['child']

    public void setChild(ChildBase child) {

        // TODO add some checking here or simply replace any child already in the set, we only want one in the set.
        addToChildren(child)
    }

    public ChildBase getChild() {
        return children?.iterator()?.next()
    }
}

On Fri, Jul 20, 2012 at 10:45 AM, Alan Bowsher <[hidden email]> wrote:
I've seen this JIRA issue:  http://jira.grails.org/browse/GRAILS-5077

I'm assuming you still can't have a lazy-loaded hasOne relationship.  With that in mind, I'm wondering what my options are.

Here's the situation:  

class Parent {
    static hasOne = [child: Child]
}

class Child {
    static belongsTo = [parent:  Parent]

   static mapping = {
        tablePerHierarchy(false)
    }
}

class Child1 extends Child {}
class Child2 extends Child {}

In our case, we have many children classes.  When the Parent is retrieved, this results in an outer join against every single ChildX table.  That's ok most of the time, but not in batch operations.  So we want to avoid that.  (we cannot easily change this design because the system has to be flexible in adding new Child types, and we don't want a single table with hundreds of columns)

Options:

1) Drop down to Hibernate mapping level?  I'm guessing from the JIRA comments this doesn't work, just checking...
2) Don't use hasOne to model the relationship?  It seems not using this for other one-to-ones we have allows them to be lazy.
3) Use straight SQL to get the Parent (using this now)
4) Query from the child up where we are able?

I tried Option 4 by querying against a specific Child, but when you get to the Parent, GORM turns around and gets the Child again even though you've already got it, so we get all those outer joins again.  Is there any way to convince GORM not to do this when I've already got the Child, such as a join fetch of the parent when getting the Child?

i.e.
Child1.get(id) // Get the parent here also so GORM sees we've already got the child and doesn't turn back around and try to get it

Thanks...




Loading...