0
votes

I have two object, a room type and a reservation. Simplified they are:

class Room {
  String description
  int quantity
}

class Reservation {
  String who
  Room room
}

I want to query for all rooms along with the number of rooms available for each type. In SQL this does what I want:

select id, quantity, occupied, quantity-coalesce(occupied, 0) as available
from room left join(select room_id, count(room_id) as occupied from reservation) 
on id = room_id;

I'm not getting anywhere trying to work out how to do this with HQL.

I'd appreciate any pointers since it seems like I'm missing something fairly fundamental in either HQL or GORM.

2

2 Answers

1
votes

The problem here is your trying to represent fields that are not your domain classes like available and occupied. Trying to get HQL\GORM to do this can be a bit a little frustrating, but not impossible. I think you have a couple options here...

1.) Build your domain classes so that there easier to use. Maybe your Room needs to know about it's Reservations via a mapping table or, perhaps write what you want the code to look like and then adjust the design.

For example. Maybe you want your code to look like this...

RoomReservation.queryAllByRoomAndDateBetween(room, arrivalDate, departureDate);  

Then you would implement it like this...

    class RoomReservation{
        ...
        def queryAllByRoomAndDateBetween(def room, Date arrivalDate, Date departureDate){
           return RoomReservation.withCriteria {
             eq('room', room)
             and {
               between('departureDate', arrivalDate, departureDate)
             }
        }
    }

2.) My second thought is... It's okay to use the database for what it's good for. Sometimes using sql in you code is simply the most effective way to do something. Just do it in moderation and keep it centralized and unit tested. I don't suggest you use this approach because you query isn't that complex, but it is an option. I use stored procedures for things like 'dashboard view's' that query millions of objects for summary data.

class Room{
    ...
  def queryReservations(){
      def sql = new Sql(dataSoruce);
      return sql.call("{call GetReservations(?)}", [this.id]) //<-- stored procedure.
  }
}
0
votes

I'm not sure how you can describe a left join with a subquery in HQL. INn any case you can easily execute raw SQL in grails too, if HQL is not expressive enough:

in your service, inject the dataSource and create a groovy.sql.Sql instance

def dataSource

[...]    

def sql= new Sql(dataSource)
sql.eachRow("...."){row->
    [...]
}

I know it's very annoying when people try to patronize you into their way of thinking when you ask a question, instead of answering your question or just shut up, but in my opinion, this query is sufficiently complex that I would create a concept for this number in my data structure, perhaps an Availability table associated to the Room, which would keep count not only of the quantity but also of the occupied value.

This is instead of computing it every time you need it.

Just my $.02 just ignore it if it annoys you.