【问题标题】:Play 2 / Scala - Generic Reactive Mongo CRUD - json serializationPlay 2 / Scala - 通用反应式 Mongo CRUD - json 序列化
【发布时间】:2015-11-09 10:27:39
【问题描述】:

我发现了一些与我的问题非常接近的问题(例如Play Framework / Scala: abstract repository and Json de/serialization),但它们并没有解决我的问题。

我想要实现的是对我的 CRUD DAO 的抽象,用于常见的 CRUD 操作。

我为此构建了一个 GenericMongoDaoActor:

abstract class GenericMongoDaoActor[T <: Entity: Writes](implicit inj:Injector, implicit val f:Format[T]) extends Actor with Injectable {
  protected val db = inject[DefaultDB]
  protected val collectionName: String
  protected val collection:JSONCollection

  //set to None to use fallback
  def defaultSelector(obj:T):Option[JsObject] = None
  def fallbackSelector(obj:T) = Json.obj("_id" -> Json.obj("$elemMatch" -> obj._id))

  protected def find(jsObject: JsObject) = {
    val currentSender = sender
    val futureOption = collection
      .find(jsObject)
      .cursor[T](ReadPreference.primaryPreferred)
      .headOption

    futureOption.mapTo[Option[T]].flatMap {
      case Some(pobj) =>
        currentSender ! Some(pobj)
        Future{pobj}
      case None =>
        currentSender ! None
        Future{None}
    }
  }

  protected def save(obj:T):Unit = {
    update(obj, true)
  }

  protected def update(obj:T):Unit = {
    update(obj, false)
  }

  private def update(obj:T, upsert: Boolean):Unit = {
    val selector = defaultSelector(obj) match {
      case None => fallbackSelector(obj)
      case Some(sel) => sel
    }
    collection.update(
      selector,
      obj,
      GetLastError.Default,
      upsert).onComplete {
      case Failure(e) => Logger.error("[" + this.getClass.getName + "] Couldn`t update " + obj.getClass.getName + ": " + Json.prettyPrint(Json.toJson(obj)), e)
      case Success(lastError) => //currentSender ! lastError todo: do something with lastError
    }
  }

  def findAll() = {
    collection.find(Json.obj()).cursor[T](ReadPreference.primaryPreferred).collect[List]()
  }

}

DAOActor 处理继承抽象类“Entity”的实体:

abstract class Entity {
  val _id: BSONObjectID
}

目前有2个类继承Entity..

如您所见,我的 DOAActor 已经绑定在上下文中,可以在范围内查找 Writes[T]..

abstract class GenericMongoDaoActor[T <: Entity: Writes]

当我尝试像这样构建我的项目时,它抱怨在更新方法中没有提供 OWrites 来序列化类型为“T”的“obj”。

No Json serializer as JsObject found for type T. Try to implement an implicit OWrites or OFormat for this type.

collection.update( <-------------

我找不到解决此问题的方法。如果可以,请告诉我。

【问题讨论】:

    标签: json scala playframework-2.0 crud reactivemongo


    【解决方案1】:

    当我从早期版本的 ReactiveMongo 迁移时,我遇到了类似的问题。对我有用的是在对 ReactiveMongo API 的各种调用中散布一些 .as[JsObject] 转换。

    所以如果我之前有:

     collection.update(
      selector,
      obj,
      ...
    )
    

    我将其替换为:

    collection.update(
      selector,
      obj.as[JsObject],
      ...
    )
    

    这似乎就足够了,尽管我正在以与您略有不同的方式提供必要的 JSON 转换器;我的抽象类的子类必须实现 implicit val fmt:Format[T] 成员。我怀疑这是否重要,但它似乎是一种有效的方法:-)

    【讨论】:

    • 这解决了我的问题。非常感谢。我仍然不明白为什么它抱怨它需要 owrites 或 oformat 在上面..
    【解决方案2】:

    您需要使用 OWrites 和 OFormat 而不是 Writes 和 Format。 我知道 OWrites 扩展了 Writes 并且 OFormat 扩展了 Format,但是您使用的 reactivemongo 版本正在等待 OWrites 和 OFormat,而不是它的超类型。

    【讨论】:

    • 不可能使用Writes 代替OWrites,因为编写与预期BSON 文档相对应的结构的特殊性必须使用JsObject,而不是JsValue(结果Writes).
    • @cchantep 我说“使用 OWrites 而不是 Writes”。 .as[JsObject] 的使用是一种技巧,而不是解决方案。最新版本的 play-reactivemongo 使用 OWrites、OFormat 等。我遇到了同样的错误。请阅读错误。
    猜你喜欢
    • 2015-10-12
    • 2015-04-28
    • 2021-10-17
    • 2015-12-12
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    相关资源
    最近更新 更多