Scala 具有依赖注入的db操作的可重用代码

Scala 具有依赖注入的db操作的可重用代码,scala,Scala,我有多个参与者管理写入mongo db的数据模型 object LevelManager { val collectionName = "levels" } @Singleton class LevelManager @Inject()( val reactiveMongoApi: ReactiveMongoApi) extends Actor with ActorLogging with InjectedActorSu

我有多个参与者管理写入mongo db的数据模型

object LevelManager {
  val collectionName = "levels"
}

@Singleton
class LevelManager @Inject()(
                                  val reactiveMongoApi: ReactiveMongoApi) extends Actor with ActorLogging  with InjectedActorSupport {

  def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection](LevelManager.collectionName))

  override def receive: Receive = {
    case msg:GetById =>
        var level = collection.flatMap(c => c.find(Json.obj("_id" -> msg.id), Option.empty[JsObject]).one[LevelModel].map {
          result =>
              logger.info( result )
     }
    }
}
这很好,但是这个db代码在每个参与者中都会使用,我并没有设法只使用一次。我不确定这是否也是一个聪明的方法。它起源于更古老的scala时代,没有依赖注入,所有东西都放在一个对象特性中

因此,我正在寻找一种特性或其他东西,具有基本的db io处理能力

编辑:在依赖项注入之前,我能够使用如下特征:

trait BaseModel[T] {

  val collectionName: String
  val db = ReactiveMongoPlugin.db


  def load(id: Long)(implicit fmt: Format[T]) = {
    val coll = db.collection[JSONCollection](collectionName)
    coll.find(Json.obj("_id" -> id)).one[T]
  }

  def loadAll()(implicit fmt: Format[T]) = {
    val coll = db.collection[JSONCollection](collectionName)
    coll.find(Json.obj()).cursor[T].collect[Vector]()
  }

  def save(id: Long, model: T)(implicit fmt: Format[T]) = {
    val coll = db.collection[JSONCollection](collectionName)
    val doc = Json.toJson(model).as[JsObject] + ("_id" -> Json.toJson(id))
    coll.save(doc).map { lastError =>
      if (!lastError.ok) Logger.error(lastError.message)
      lastError.ok
    }
  }

最后,我用def collection:Future[JSONCollection]创建了一个trait,现在我可以访问我最喜欢的db函数了。这是我的目标,让生活变得更好。但我对最近的反馈感到不安,如果这有任何缺点的话

trait DBStuff[T] {
  def collection: Future[JSONCollection]
  def log: LoggingAdapter

  def save(id: String, model: T)(implicit fmt: Format[T]) = {
    val doc:JsObject = Json.toJson(model).as[JsObject] + ("_id" -> Json.toJson(id))
    collection.flatMap(_.update.one(Json.obj("_id" -> id), doc, true)).map(lastError => if (!lastError.ok) log.warning(s"Mongo LastError: %s".format(lastError)))
  }

  def loadOne(id: String)(implicit fmt: Format[T]): Future[Option[T]] = loadOne( Json.obj("_id" -> id) )

  def loadOne(obj: JsObject, projection:Option[JsObject] = None )(implicit fmt: Format[T]): Future[Option[T]] = {
    collection.flatMap(_.find( obj, projection).one[T].map {
      result =>
        result
    }.recover {
      case err => log.error(s"DB Loading Error: $err")
        None
    })
  }

  def loadAll()(implicit fmt: Format[T]):Future[Vector[T]] = {
    loadAll(Json.obj(), None )
  }

  def loadAll( obj: JsObject, projection:Option[JsObject] = None)(implicit fmt: Format[T]):Future[Vector[T]] = {
    collection.flatMap(_.find(obj, projection ).cursor[T]().collect[Vector](Int.MaxValue, Cursor.FailOnError()).map {
      result => result
    }.recover {
      case err =>
        log.error(s"DB Loading Error: $err")
        Vector.empty
    })
  }
  ...
}

你为什么要那样做?为什么不保持简单呢?ReactiveMongo已经在管理IO和并发。我不喜欢10次类似的db查询来加载、保存和删除条目。使用save、load和delete函数而不必使用ReactiveMongo查询对我来说听起来像是“保持简单;”彻底改造actor DB并发性绝对不简单,也不是避免代码重复的唯一方法。。。看起来像是一个x/y问题,对于meSo来说,有十倍的重复代码是最好的方法?请检查我的编辑,也许这可以解释更多我想要的
@Singleton
class TaskManager @Inject()(
                             val reactiveMongoApi: ReactiveMongoApi
                            ) extends Actor with ActorLogging with InjectedActorSupport with DBStuff[TaskModel] {

    def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection](TaskManager.collectionName))

    override def preStart() = {

    loadAll() map {
      result =>
        //What ever
    }
}