Question

I have a couple scenarios where I want to retrieve a single Advertiser and eager fetch most of its object graph. I definitely don't want to do this by default, so I've been searching for the right way to do this for a single query. This is what I've come up with so far:

    Advertiser.createCriteria().get {
        eq('id', id)
        createAlias('foos', 'foos', CriteriaSpecification.LEFT_JOIN)
        createAlias('foos.bars', 'bars', CriteriaSpecification.LEFT_JOIN)
        createAlias('bars.baz', 'bazzes', CriteriaSpecification.INNER_JOIN)
    }

This works, but I dislike it for a couple reasons.

  1. It seems like a very indirect and unintuitive way to say "just join the dang tables please."
  2. There is no compile time checking. If the foos association didn't exist on an Advertiser, the compiler would not care.

Here's how I'd really love to see it work:

Advertiser.where {
    id == id
    foos {
        bars {
            baz
        }
    }
}

But this doesn't do any joining; apparently, if you're not actually specifying conditions for that property (>, <, ==, etc) it will just ignore you.

What are my options? How can I, at bare minimum, make this more intuitive to read? Looking for the closest to my ideal as I can get.

Edit

I've tried some of the suggestions below and things aren't working, and it may be partially because I'm not getting my syntax right. Let's say that I need to eager fetch an additional 1st level association called whatsits

I'm trying to do it this way:

Advertiser.withCriteria {
    idEq(id)
    whatsits
    foos {
        bars {
            baz 
        }
    }
}

I've also tried

Advertiser.withCriteria {
    idEq(id) && whatsits && foos {
        bars {
            baz
        }
    }
}

But different approaches yield different exceptions, strange looking queries, etc.

Was it helpful?

Solution

This isn't too far from your first example, but you may or may not find it more intuitive?

def result = Advertiser.withCriteria {
    eq('id', id)
    fetchMode 'foos', FetchMode.JOIN
    fetchMode 'foos.bars', FetchMode.JOIN
    fetchMode 'bars.baz', FetchMode.JOIN
}

OTHER TIPS

You can use DSLs in createCriteria/withCriteria as you have used in the where clause, they are by default eagerly fetched. You get result as a list, so result[0] should be it.

def result = Advertiser.withCriteria {
    idEq(id)
    foos{
       bars{
          baz{

          }
       }
    }
}

After getting the result back you can check whether you have the associations present, that is,

if(result[0].foos){...}

UPDATE

Refer this Sample Code for details.

UPDATE2

&&,||,== cannot be used in a criteria. They have dedicated DSL's for the same operations like and{}, or{}, eq(). Have a look at Grails Criteria

Advertiser.withCriteria {
    idEq(id)
    whatsits{}
    foos {
        bars {
            baz
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top