1

In our application we have a Player which can have game and practice plans, therefore we designed the abstract class Plan and two derived classes GamePlan and PracticePlan. In the database derived classes are saved into a single table with 'class' attribute.

When we use getPlans() on a specific player we get all the plans, but we would like to know how to get only Game or Practice plans. Something like player.getPracticePlans() or Player.PracticePlans(player_id). Below are our classes.

class Player  {

    String name
    static hasMany = [ plans : Plan] 
}

abstract class Plan {
}

class PracticePlan extends Plan{
}

class GamePlan extends Plan{
}

Note: We tried to use something like:

def query = Player.where {
    plans {  class == "GamePlan" }
}   

But the class is a reserved keyword and it doesn't compile.

MBozic
  • 1,132
  • 1
  • 10
  • 22
  • Does you Plan class `belongTo` Player? – tim_yates Jun 29 '12 at 14:23
  • No, one plan can be shared among many users. – MBozic Jun 29 '12 at 14:41
  • Personally, I'd just do static hasMany = [gamePlans: GamePlan, practicePlans: PracticePlan]. Wouldn't that simplify things? – Gregg Jun 29 '12 at 17:01
  • Maybe we will go with approach you suggested, probably there would be less problems this way, but the reason we wanted them together is because the logic for both is the same so we wouldn't have duplicate code I guess. – MBozic Jul 02 '12 at 08:26

2 Answers2

1

I believe you can do this to load all plans for a Person, then filter out the unwanted ones:

def gamePlansForPlayer = Player.get( id ).plans.findAll { plan ->
  plan.instanceOf( GamePlan )
}

Not tested it though :-(

tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • It works, thank you! Can you answer me please, does hibernate loads all Plan instances from common table for GamePlan and PracticePlan and filters them on application level or it does this in query? If it loads everything would it be better to say that Player has PracticePlans and GamePlans separately? – MBozic Jun 29 '12 at 15:05
  • This will load all plans for a `Player` into memory, then filter that list down to just the `GamePlan` instances. I would wait for a bit with this question as someone else may know a way to write HQL or a Criteria to do this at database level and avoid this overhead... – tim_yates Jun 29 '12 at 15:11
0

You should be able to get the class with getClass(). See this answer: Groovy / grails how to determine a data type?.

You could also use a Criteria, which will put the column into quotes so it's not running up against the reserved word problem:

def plans = Player.withCriteria {
    plans {
        eq('class', "com.name.space.GamePlan")
    }
}

(Note that I'm specifying the classname with the namespace, as that's how it's stored in my experience. YMMV.)

If this works and you want to make it more general, you can make it into a named query and provide the class as a parameter:

def namedQueries = {
    plansByClass = { clazz ->
        plans {
            eq('class', clazz)
        }
    }
}

You then call this like a static method:

def plans = Player.plansByClass('GamePlan')

Note that, while I do use Criteria in my applications, these particular examples are not tested.

Community
  • 1
  • 1
Charles Wood
  • 864
  • 8
  • 23