I'm new to Slick and Scala. First of take a look at my example table with case class mapping and helper for queries SuitsManager
. Now methods of SuitsManager
are called by Play! controllers inside DBAction (I'm using play-slick 0.6.0.1).
package models
import play.api.db.slick._
import play.api.db.slick.Config.driver.simple._
import scala.collection.immutable.HashMap
import scala.slick.jdbc.JdbcBackend
case class Suit(id:Option[Long],
complainant: String,
defender: String,
litigation: Long,
litigationValue: BigDecimal,
status: Long)
class Suits(tag: Tag) extends Table[Suit](tag, "SUITS") {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def complainant = column[String]("complainant")
def defender = column[String]("defender")
def litigation = column[Long]("litigation")
def litigationValue = column[BigDecimal]("litigationValue")
def status = column[Long]("status")
def * = (id.?, complainant, defender, litigation, litigationValue, status) <> (Suit.tupled, Suit.unapply)
}
object SuitsManager {
val suits = TableQuery[Suits]
def list(offset: Int, limit: Int, filter: String = "%")(implicit session: JdbcBackend#Session) = {
suits.filter(_.defender like "%").drop(offset).take(limit).list
}
def count(offset: Int, limit: Int, filter: String = "%") : Long = {
suits.filter(_.defender like "%").drop(offset).take(limit).length.run
}
}
Now take a look at 2 methods in SuitsController
the first one compiles because it declares implicit session parameter. The second one gives compile error:
could not find implicit value for parameter session: play.api.db.slick.Config.driver.Backend#Session
So creating helper objects for queries seems to be not very elegant. Is there any other way do it without declaring implicit session parameter? Maybe using an import? My second question: is the session parameter type JdbcBackend#Session
correct? Why not just Session?
You can make it a helper class and session an argument of the class, if the repetition bothers you. It's explained here: http://slick.typesafe.com/doc/2.0.1/connection.html#passing-sessions-around
The import-solution you suggested exists as well, but it is less typesafe. See: http://slick.typesafe.com/doc/2.0.1/connection.html#dynamically-scoped-sessions
Session is a path-dependent type in the Slick driver cake (as in cake pattern), that's why it needs to be accessed via the # operator
First question: It is not possible to avoid passing around the
Session
in some way.The implicit
Session
you pass around is not some global information of your application. TheSession
object represents the current open session you have with the database. With Play Slick, this database session is opened for you when a request is made to aDBAction
.That means that your
Session
is only available, and strictly tied to, an HTTP request. In fact, you'll find that it is a field of theimplicit request =>
you note in everyDBAction
:So you have a new and different database session for every request. Furthermore, every database interaction requires a database session. Therefore, every method that executes some query therefore needs to be provided with the current
Session
you have for processing your particular request.The reason implicits are usually used for this is because it provides the cleanest code for passing around this session.
Versus the more repetitive
The example in the Slick documentation question that @cvogt mentions is not a good solution to your problem, as it does not reduce the amount of arguments you need to pass around in this case.
Second question: In general,
Session
is a so-called type alias for forJdbcBackend#Session
. That means thattype Session = JdbcBackend#Session
, i.e. they're exactly the same. You can safely useSession
in any code except, unfortunately, Play controller code.The reason for this is that Play controllers also define a type
Session
. Play'sSession
represents the current HTTP session, based on the cookies the user has set. Unfortunately, this naming clashes with Slick'sSession
.To work around this, you can alias the import:
import scala.slick.driver.JdbcProfile.simple.{Session => SlickSession}
.