Question

I am about to start my first project in the Lift framework and I have to decide which persistence library to choose. I am about to use relational backend so both Mapper and Record may come in play.

In case of Mapper - the thing I miss the most is the ability to control the queries being sent to the RDBMS - especially when it comes to more complicated queries which would be solved by joins, aggregation etc in SQL. Take the following example - let's have following two entities:

class BaseProduct extends LongKeyedMapper[BaseProduct] with IdPK {
  // some fields
}
object BaseProduct extends BaseProduct with LongKeyedMetaMapper[BaseProduct]

class MyProduct extends LongKeyedMapper[MyProduct] with IdPK {
  // some fields
  object base extends MappedLongForeignKey(this, BaseProduct)
}
object MyProduct extends MyProduct with LongKeyedMetaMapper[MyProduct]

Where MyProduct is one of the specialization of the BaseProduct entity. There is obviously a one-to-one relation between these entities. However the best possibility I've come up with to query for the exact MyProduct together with its BaseProduct was a query like this:

MyProduct.findAll(PreCache(MyProduct.base))

Which issues two queries (moreover I am afraid I am not able to control which fields of the MyProduct entity I want to select.

Enough bad for the Mapper library. My main concern about the Record/Squeryl API is the fact that it lacks all those Proto-classes that are present around the Mapper API. Is there something close to the functionality of these classes for the Record? Is it possible to access database specific features in Squeryl (eg. geometrical queries in PostgreSQL)?

Are there any other pros and cons for either of these layers? Or is there any other abstraction layer which would deserve attention if I want to have decent typesafe encapsulation of the communication with the database and which would provide decent control over the queries (I was used to issuing queries directly using the PDO layer in PHP - I don't want such a direct querying interface but some possibility of having control over queries would be great) Integration with Lift framework is definitely an advantage.

Thank you!

Was it helpful?

Solution

We've been using Squeryl with Lift for quite a while and have been very happy with it. Based on your case above, in the current release version of Squeryl (0.9.5), you could do something like:

class BaseProduct(id:Long, some more fields) extends KeyedEntity[Long] {

}

class MyProduct(id:Long, some more fields) extends KeyedEntity[Long] {

}

Then, you would have a schema that defines the relationships like (I am assuming they are joined on the ID field):

val baseProducts = Table[BaseProduct]("base_products")
val myProducts = Table[MyProduct]("my_products")
val myProductsToBaseProducts = 
  oneToManyRelation(myProducts, baseProducts).via((mp, bp) =>
    mp.id === bp.id)

To query both records, you would do something like:

from(myProducts, baseProducts) ( (mp, bp) =>
  where(mp.id === bp.id and mp.id === LOOKUPVAL) 
  select(bp, mp) )

The query above will return a tuple of (BaseProduct, MarketProduct) from a single SQL select.

You can also use the relationship to retrieve the related item, such as by adding this method to MyProduct:

def baseProduct = myProductsToBaseProducts.left(this)

However, like your example from Mapper, it will issue a second query. As for making database specific queries, there is the & operator which will allow you to evaluate expressions at the server. If the function is not available in Squeryl you can create custom functions.

Overall, I have found Squeryl to be very flexible and a great hybrid between ORM and straight SQL. It has performed remarkably well and I have not found too many places where Squeryl prohibited me from easily getting at the database functionality that I needed. It gets even easier with the next version, as 0.9.6 will have a lot more flexibility with custom types.

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