以优雅的方式传递Slick 2.0隐式会话 [英] Passing Slick 2.0 implicit session in elegant way

查看:83
本文介绍了以优雅的方式传递Slick 2.0隐式会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Slick和Scala的新手.首先看一下我的示例表,其中包含案例类映射和查询SuitsManager的帮助器.现在SuitsManager的方法被Play调用! DBAction内部的控制器(我使用的是平滑播放0.6.0.1).

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
  }
}

现在来看一下SuitsController中的2个方法,第一个方法可以编译,因为它声明了隐式的会话参数.第二个给出了编译错误:

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

因此,为查询创建助手对象似乎不是一件很优雅的事情.还有其他方法可以不声明隐式会话参数吗?也许使用导入?我的第二个问题:会话参数类型JdbcBackend#Session是否正确?为什么不只是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?

推荐答案

第一个问题: 无法避免以某种方式绕过Session.

First question: It is not possible to avoid passing around the Session in some way.

您传递的隐式Session不是您的应用程序的某些全局信息. Session对象代表您与数据库的当前打开会话.使用Play Slick,当向DBAction发出请求时,将为您打开此数据库会话.

The implicit Session you pass around is not some global information of your application. The Session 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 a DBAction.

这意味着您的Session仅适用于HTTP请求,并且严格与HTTP请求绑定.实际上,您会发现它是您在每个DBAction中记录的implicit request =>的字段:

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 the implicit request => you note in every DBAction:

val someAction = DBAction { implicit request =>      // DBAction opens database session, and puts it in request.dbSession
   // Database session for this request is implicitly available on
   // the scope here and therefore may be passed to other methods implicitly
}  // Database session is closed

因此,每个请求都有一个新的不同的数据库会话.此外,每次数据库交互都需要一个数据库会话.因此,每个执行某些查询的方法都需要提供用于处理特定请求的当前Session.

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.

// With implicits
def helperMethod1(param: Any)(implicit s: Session) = someQuery1.list // Session is passed implicitly 
def helperMethod2(param: Any)(implicit s: Session) = someQuery2.exists.run // Session is passed implicitly

def action = DBAction { implicit request =>
   // Stuff
   helperMethod1(param1) // request.dbSession is passed implicitly
   // Stuff
   helperMethod2(param2) // request.dbSession is passed implicitly
   // Stuff
}

相对于重复性

// Without implicits
def helperMethod1(param: Any, s: Session) = someQuery.list(s)  // Must pass Session explicitly
def helperMethod2(param: Any, s: Session) = someQuery.exists.run(s)

def action = DBAction { implicit request =>
   val session = request.dbSession
   // Stuff
   helperMethod1(param1, session) // Have to repeat session for every DB call
   // Stuff
   helperMethod2(param2, session)
   // Stuff
}

@cvogt提到的Slick文档问题中的示例不是解决问题的好方法,因为它不会减少在这种情况下需要传递的参数数量.

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.

第二个问题: 通常,SessionJdbcBackend#Session的所谓类型别名.这意味着type Session = JdbcBackend#Session,即它们是完全相同的.您可以在任何代码中安全地使用Session,但不幸的是,播放控制器代码除外.

Second question: In general, Session is a so-called type alias for for JdbcBackend#Session. That means that type Session = JdbcBackend#Session, i.e. they're exactly the same. You can safely use Session in any code except, unfortunately, Play controller code.

这样做的原因是,播放控制器还定义了类型Session. Play的Session根据用户设置的cookie表示当前的HTTP会话.不幸的是,这种命名与Slick的Session冲突.

The reason for this is that Play controllers also define a type Session. Play's Session represents the current HTTP session, based on the cookies the user has set. Unfortunately, this naming clashes with Slick's Session.

要解决此问题,您可以为导入添加别名:import scala.slick.driver.JdbcProfile.simple.{Session => SlickSession}.

To work around this, you can alias the import: import scala.slick.driver.JdbcProfile.simple.{Session => SlickSession}.

这篇关于以优雅的方式传递Slick 2.0隐式会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆