【问题标题】:ReactiveMongo mapping from ObjectId to case class BSONObjectID从 ObjectId 到案例类 BSONObjectID 的 ReactiveMongo 映射
【发布时间】:2015-03-09 10:13:11
【问题描述】:

我是 Scala 和 Play 的新手,我正在尝试将 Scala BSONObjectID 映射到 mongo ObjectId。我从互联网上获得了许多样本,但仍然陷入一个编译时错误。以下是我的案例类的代码:

case class UserDetail(
 val _id: Option[BSONObjectID],
 val name: String,
 val age: Double,
 var created: Option[Long]
)  

object UserDetail{
 implicit val userDetailReads: Reads[UserDetail] = (
 (JsPath \ "_id").readNullable[BSONObjectID] and
 (JsPath \ "name").read[String] and
 (JsPath \ "age").read[Double] and
 (JsPath \ "created").readNullable[Long]
)(UserDetail.apply _)

implicit val userDetailWrites: Writes[UserDetail] = (
(JsPath \ "_id").writeNullable[BSONObjectID]and
(JsPath \ "name").write[String] and
(JsPath \ "age").write[Double] and
(JsPath \ "created").writeNullable[Long]
)(unlift { UserDetail.unapply })}

这个(JsPath \ "_id").readNullable[BSONObjectID]产生编译时错误如下:

not enough arguments for method readNullable: (implicit r: play.api.libs.json.Reads[reactivemongo.bson.BSONObjectID])play.api.libs.json.Reads[Option[reactivemongo.bson.BSONObjectID]]. Unspecified value parameter r.
not enough arguments for method readNullable: (implicit r: play.api.libs.json.Reads[reactivemongo.bson.BSONObjectID])play.api.libs.json.Reads[Option[reactivemongo.bson.BSONObjectID]]. Unspecified value parameter r.

这个(JsPath \ "_id").writeNullable[BSONObjectID] 也会产生同样的错误。

我想格式化我的 json 请求。所以我使用自定义格式化程序如下:

object BSONObjectIDFormat extends Format[BSONObjectID]{

 def writes(objectId: BSONObjectID): JsValue = JsString(objectId.toString())

 def reads(json: JsValue): JsResult[BSONObjectID] = json match {
  case JsString(x) => {
  val maybeOID: Try[BSONObjectID] = BSONObjectID.parse(x)
  if(maybeOID.isSuccess) JsSuccess(maybeOID.get) else {
    JsError("Expected BSONObjectID as JsString")
  }
}
case _ => JsError("Expected BSONObjectID as JsString")
}}

我的Json请求如下:

{
"_id":{"$oid":"54fd4b7084071e6a6ab13cee"},
"name" : "Akka",
"age" : 30,
"created" : 1425886070013
}

当我发送 JSON 请求时,出现以下错误:

[error] D:\play_projects\scala_play_sample\app\models\UserDetail.scala:35: No Js
on deserializer found for type reactivemongo.bson.BSONObjectID. Try to implement
an implicit Reads or Format for this type.
[error]     (JsPath \ "_id").readNullable[BSONObjectID] and
[error]                                  ^
[error] D:\play_projects\scala_play_sample\app\models\UserDetail.scala:42: No Js
on serializer found for type reactivemongo.bson.BSONObjectID. Try to implement a
n implicit Writes or Format for this type.
[error]     (JsPath \ "_id").writeNullable[BSONObjectID]and

【问题讨论】:

    标签: scala playframework-2.3 play-reactivemongo


    【解决方案1】:

    在这种情况下,我们只需在 Case 类中初始化我们的自定义格式化程序。我不确定,为什么播放不自动 pic 格式。现在代码如下:

    case class UserDetail(
     val _id: Option[BSONObjectID],
     val name: String,
     val age: Double,
     var created: Option[Long]
    )  
    
    object UserDetail{
    
     implicit val idFormatter = BSONObjectIDFormat
    
     implicit val userDetailReads: Reads[UserDetail] = (
     (JsPath \ "_id").readNullable[BSONObjectID] and
     (JsPath \ "name").read[String] and
     (JsPath \ "age").read[Double] and
     (JsPath \ "created").readNullable[Long]
    )(UserDetail.apply _)
    
     implicit val userDetailWrites: Writes[UserDetail] = (
     (JsPath \ "_id").writeNullable[BSONObjectID]and
     (JsPath \ "name").write[String] and
     (JsPath \ "age").write[Double] and
     (JsPath \ "created").writeNullable[Long]
     )(unlift { UserDetail.unapply })}
    

    【讨论】:

    • 通常不建议在模型的案例类中使用 BSON 特定类型。它将应用模型的定义与底层持久性库的详细实现联系起来。
    • Hello @cchantep 而不是 BSON 特定类型。我们需要使用什么?因为当我使用 String 类型时,我无法进行诸如 find by id 之类的查询。
    【解决方案2】:

    对于 reactivemongo 1.0.7,将 ObjectId 映射到案例类非常容易。

    ReadsMacros 对于大多数情况来说已经足够了。

    import reactivemongo.api.bson.Macros.Annotations.{Key, Reader}
    import reactivemongo.api.bson.{BSONDocumentHandler, BSONObjectID, BSONReader, Macros}
    
    object Model {
      val idReader: BSONReader[String] = BSONReader.collect[String] { case id @ BSONObjectID(_) =>
        id.asInstanceOf[BSONObjectID].stringify
      }
    
      case class Post(@Reader(idReader) @Key("_id") id: String, title: String, content: String, created: Long)
    
      implicit val postHandler: BSONDocumentHandler[Post] = Macros.handler[Post]
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 2010-11-16
      相关资源
      最近更新 更多