Scala Play Framework Slick Session的问题

Mik*_*icz 1 mysql scala playframework playframework-2.0 slick

我正在使用Play 2.2在Scala中创建一个应用程序.我play-slick 0.5.0.8用作MySQL DB连接器.我有以下应用程序控制器:

package controllers

import models._
import models.database._

import play.api._
import play.api.mvc._
import play.api.Play.current
import play.api.db.slick._

object Application extends Controller {
  // WORKS:
  def test = DBAction {
    implicit session => Ok(views.html.test(Cameras.findById(1)))
  }

  // DOES NOT WORK:
  def photo = Action {
    val p = PhotoFetcher.fetchRandomDisplayPhoto(someParametersBlah))
    Ok(views.html.photo(p))
  }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,testDBAction 可以正常工作,并且能够从数据库中获取照片.不幸的是,photo行动不起作用.

PhotoFetcher.fetchRandomDisplayPhoto(blah)做了很多不同的事情.埋在里面的是一个调用Cameras.findById(blah),它应该返回一个Camera对象(在testDBAction中工作).但是,使用此配置,我收到以下错误:

could not find implicit value for parameter s: slick.driver.MySQLDriver.simple.Session
Run Code Online (Sandbox Code Playgroud)

我已经尝试将photoAction转换为DBAction,如下所示:

def photo = DBAction {
  implicit session => {
    val p = PhotoFetcher.fetchRandomDisplayPhoto(someParametersBlah))
    Ok(views.html.photo(p))
  }
}
Run Code Online (Sandbox Code Playgroud)

但这只会导致相同的遗失会话错误.这就像PhotoFetcher不知道隐式会话.

我试过的另一件事是导入slick.session.Database.threadLocalSession我的PhotoFetcher,但这只会导致以下错误:

SQLException: No implicit session available; threadLocalSession can only be used within a withSession block
Run Code Online (Sandbox Code Playgroud)

如果有任何帮助,这是我的Cameras对象的简化版本:

package models.database

import models.Format.Format
import scala.slick.driver.MySQLDriver.simple._

case class Camera(id: Long,
                  otherStuff: String)

trait CamerasComponent {
  val Cameras: Cameras

  class Cameras extends Table[Camera]("cameras") {
    def id          = column[Long]("id", O.PrimaryKey, O.AutoInc)
    def otherStuff  = column[String]("otherStuff", O.NotNull)

    def * = id ~ otherStuff <> (Camera.apply _, Camera.unapply _)

    val byId         = createFinderBy(_.id)
    val byOtherStuff = createFinderBy(_.otherStuff)
  }
}

object Cameras extends DAO {
  def insert(camera: Camera)(implicit s: Session) { Cameras.insert(camera) }
  def findById(id: Long)(implicit s: Session): Option[Camera] = Cameras.byId(id).firstOption
  def findByOtherStuff(otherStuff: String)(implicit s: Session): Option[Camera] = Cameras.byOtherStuff(model).firstOption
}
Run Code Online (Sandbox Code Playgroud)

所以,好像我已经在某处交叉了.现在,我只能直接从Controller DBAction访问我的DAO对象,而不是从一些不同的类内部访问.任何帮助,将不胜感激.谢谢!

Fai*_*aiz 5

您的定义是否PhotoFetcher.fetchRandomDisplayPhoto.fetchRandomDisplayPhoto采用隐式会话?

 // PhotoFetcher
 def fetchRandomDisplayPhoto(args: Blah*)(implicit s: Session) = {
   // ...
   val maybeCam = Cameras.findById(blah) // <- sees the implicit session 
   // ...
 }
Run Code Online (Sandbox Code Playgroud)

或者你依靠threadLocalsessionin PhotoFetcher?(没有隐含的会话参数fetchRandomDisplayPhoto)?

虽然Slick的threadLocalSession对于快速尝试的东西很方便,但它可能导致混乱和以后失去清晰度.最好只(implicit s: Session)为所有调用Slick模型的方法使用显式参数列表.这也很好DBAction,让框架管理会话.

缺点是你必须拥有(implicit s: Session)所有方法 - 有这样的解决方法:https: //github.com/freekh/play-slick/issues/20

Scala并不冗长,并且非常适合重构 - 所以我建议你考虑跨过那座桥,并DBAction用于做数据库工作的所有动作; 给所有调用数据库模型的方法提供一个隐式会话,并查看给你的里程数.