Question

I have a liftweb application in which I use Record/Squeryl as an ORM framework. Here is my schema:

object AppSchema extends Schema {
  import org.squeryl.dsl.OneToManyRelation

  val groups = table[Group]("groups")
  val domains = table[Domain]("domains")

  val groupToDomains =
    oneToManyRelation(groups, domains).
      via((g, d) => g.id === d.groupId)
}

object Group extends Group with MetaRecord[Group] with Loggable {

}

class Group extends Record[Group] with KeyedRecord[Long] with Loggable {
  override def meta = Group
  @Column(name = "id") override val idField = new LongField(this)
  val name = new StringField(this, 700, "")
  @Column(name = "date_added") val createdAt = new DateTimeField(this)

  lazy val domains: OneToMany[Domain] = AppSchema.groupToDomains.left(this)
}

object Domain extends Domain with MetaRecord[Domain] with Loggable {

}

class Domain extends Record[Domain] with KeyedRecord[Long] {
  override def meta = Domain

  @Column(name = "id") override val idField = new LongField(this)
  @Column(name = "group_id") val groupId = new LongField(this)
  val name = new StringField(this, 700, "")
  @Column(name = "date_added") val createdAt = new DateTimeField(this)

  lazy val group: ManyToOne[Group] = AppSchema.groupToDomains.right(this)  
}

I'm trying to implement a function which counts domains in a group:

def countDomainsInGroup(group: Group): Long = {
  val l = from(AppSchema.domains)(d => where(d.groupId === group.id) compute(count()))
  println("Count domains: " + l.statement)
  l.single.measures
}

This generates the following SQL:

Select
  count(*) as c0
From
  domains domains1
Where
  (domains1.group_id = 45)

Now everything is OK with that, but I suppose there should be a shortcut, as we already have group.domains, which has the proper WHERE statement defined. But when I try to use it like this:

def countDomainsInGroup(group: Group): Long = {
  val l = from(group.domains)(d => compute(count()))
  println("Count domains: " + l.statement)
  l.single.measures
}

I get the following SQL generated:

Select
  count(*) as c0
From
  (Select
     domains8.name as domains8_name,
     domains8.id as domains8_id,
     domains8.group_id as domains8_group_id,
     domains8.date_added as domains8_date_added,
   From
     domains domains8
   Where
     (45 = domains8.group_id)
  )  q1

As you can see, a subquery is generated here, which I don't need. What am I doing wrong?

Was it helpful?

Solution

If you take a closer look at OneToMany / ManyToOne, you'll see that they extend Query. They are basically a convenience for executing a query that retrieves all of the objects related to a parent or child by primary key. If you look at it that way, the SQL you see isn't surprising. You are asking for the count of the results of the query, and Squeryl is purposely pretty literal when outputting SQL so that you can optimize things yourself without worrying about rewriting. If a subquery isn't optimal, there is no reason why you would have to compute your count on the relation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top