首页 > 解决方案 > 具有依赖注入的数据库操作的可重用代码

问题描述

我有多个参与者管理写入 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 )
     }
    }
}

这工作得很好,但是这个数据库代码被用于每个演员,我没有设法只拥有它一次。我不确定这是否也是一个聪明的方法。它源自没有依赖注入的旧 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
    }
  }

标签: scala

解决方案


最后我用def collection: Future[JSONCollection]创建了一个特征,现在我可以访问我最喜欢的 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
    })
  }
  ...
}
@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
    }
}

推荐阅读