2016-07-22 28 views
0

我有一個使用SqLite的play-scala應用程序。我的表是這樣定義的:在演員中動態訪問數據庫

@Singleton 
class DataSets @Inject()(protected val dbConfigProvider: DatabaseConfigProvider, keys: PublicKeys) extends DataSetsComponent 
    with HasDatabaseConfigProvider[JdbcProfile] { 
    import driver.api._ 

    val DataSets = TableQuery[DataSetsTable] 

    def all = db.run(DataSets.sortBy { _.id }.result) 
    ... 
} 

我控制器通過DI可以訪問:

@Singleton 
class DataSetsController @Inject() (dataSets: DataSets, env: play.Environment) extends Controller { 
... 

如何在演員獲得數據庫處理?

class TrainActor @Inject() (dataSets: DataSets) extends Actor { 
... 

當然不起作用,因爲Guice沒有找到DataSets類。

編輯:澄清:我不想在控制器中使用actor來訪問數據庫(通過ask),而是在請求之後從控制器啓動一些資源密集型計算並將它們存儲在db中之後(異步)。

回答

1

我現在發現了一種與DI集成的方式,緊跟在official documentation之後。因爲需要ActorContext,因此InjectedActorSupport只能由Actor繼承。這意味着我必須創建一個與實例化並啓動新的「工作者」Actor無關的參與者。也許有一種更簡單的方法,但這是正確的。

TrainActor.scala

package actors 

import javax.inject.Inject 

import akka.actor._ 
import com.google.inject.assistedinject.Assisted 
import models.{DataSet, Model, PublicKey} 
import play.api.Logger 
import tables.DataSets 

import scala.concurrent.ExecutionContext.Implicits.global 

object TrainActor { 
    case object Start 
    case class LoadData(d: DataSet, k: PublicKey) 

    trait Factory { 
    def apply(model: Model): Actor 
    } 
} 

class TrainActor @Inject() (val dataSets: DataSets, @Assisted val model: Model) extends Actor { 
    import TrainActor._ 

    def receive = { 
    case Start => 
     dataSets.findWithKey(model.id.get) 
     ... 

TrainActorStarter.scala

package actors 

import javax.inject.Inject 

import akka.actor.{Actor, ActorRef} 
import models.Model 
import play.api.libs.concurrent.InjectedActorSupport 

object TrainActorStarter { 
    case class StartTraining(model: Model) 
} 

/** 
    * https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors 
    * @param childFactory 
    */ 
class TrainActorStarter @Inject() (childFactory: TrainActor.Factory) extends Actor with InjectedActorSupport { 
    import TrainActorStarter._ 

    def receive = { 
    case StartTraining(model: Model) => 
     val trainer: ActorRef = injectedChild(childFactory(model), s"train-model-model-${model.id.get}") 
     trainer ! TrainActor.Start 
    } 
} 

ActorModule.scala

package actors 

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

class ActorModule extends AbstractModule with AkkaGuiceSupport { 
    def configure(): Unit = { 
    bindActor[TrainActorStarter]("train-actor-starter") 
    bindActorFactory[TrainActor, TrainActor.Factory] 
    } 
} 

終於在控制器:

package controllers 

import javax.inject._ 

import actors.{TrainActorStarter, TrainCallbackActor} 
import akka.actor.{ActorRef, ActorSystem, _} 
import akka.stream.Materializer 
... 

@Singleton 
class ModelsController @Inject() (implicit system: ActorSystem, materializer: Materializer, ..., @Named("train-actor-starter") trainActorStarter: ActorRef) extends Controller with InjectedActorSupport { 

    def startTraining(model: Model): Unit = { 
    if(model.id.isEmpty) return 
    trainActorStarter ! TrainActorStarter.StartTraining(model) 
    } 
0

你可以依賴注入演員:

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
    bindActor[TrainActor]("injected-train-actor") 
    } 
} 

,只是注入演員後到控制器:

class MyController @Inject()(@Named("injected-train-actor") trainActor: ActorRef) { 

    def endpointTest = Action.async { 
    for { 
     items <- (trainActor ? FetchAll).mapTo[Seq[DataSetsTableRow]] 
    } yield Ok(Json.toJson(items)) 
    } 

} 
+0

如果我想能夠在控制器中實例化新角色而不是發送消息給另一個,該怎麼辦? – joni

0

,而不必

@Singleton 
class DataSets 

一個可以聲明爲簡單的scala對象,可以充當DataSetsDAO

object DataSets 

,然後在演員只是用DataSets.dbOperation只是牢記的是,結果類型將是今後的一個,所以只安排一個消息中自上onComplete演員,以避免任何副作用。

+0

hm我認爲這將是一個簡單的解決方案,但隨後測試正在變得不可能 – joni

+0

您可以在測試數據庫上運行集成測試,否則只需通過actor Props http://doc.akka從控制器中傳入注入的DataSets實例.IO /文檔/阿卡/ 2.4.8 /斯卡拉/ actors.html#道具 –