0

有谁知道如何使用subset2将 DBObject 解析为案例类对象?超级简洁的文档对我没有帮助:(

考虑以下案例类

case class MenuItem(id : Int, name: String, desc: Option[String], prices: Option[Array[String]], subitems: Option[Array[MenuItem]])

object MenuItem {
  implicit val asBson = BsonWritable[MenuItem](item =>
    {
      val buf: DBObjectBuffer = DBO("id" -> item.id, "name" -> item.name)
      item.desc match { case Some(value) => buf.append("desc" -> value) case None => }
      item.prices match { case Some(value) => buf.append("prices" -> value) case None => }
      item.subitems match { case Some(value) => buf.append("subitems" -> value) case None => }
      buf()
    }
  )
}

我写了这个解析器

val menuItemParser: DocParser[MenuItem] = int("id") ~ str("name") ~ str("desc").opt ~ get[Array[String]]("prices").opt ~ get[Array[MenuItem]]("subitems").opt map {
  case id ~ name ~ desc_opt ~ prices_opt ~ subitems => {
    MenuItem(id, name, desc_opt, prices_opt, subitems)
  }
}

如果我删除最后一个字段,它会起作用subitems。但是上面显示的版本无法编译,因为MenuItem有引用自身的字段。它给了我以下错误

Cannot find Field for Array[com.borsch.model.MenuItem]
    val menuItemParser: DocParser[MenuItem] = int("id") ~ str("name") ~ str("desc").opt ~ get[Array[String]]("prices").opt ~ get[Array[MenuItem]]("subitems").opt map {
                                                                                                                                                 ^

它显然不能编译,因为 lastget想要Field[MenuItem]隐式。但是,如果我将其定义为MenuItem,那不是几乎是复制粘贴DocParser[MenuItem]吗?

你会如何优雅地做到这一点?

4

1 回答 1

2

我是 Subset(1.x 和 2)的作者。

自述文件指出您需要Field[T]每个T您想阅读的内容(它在“反序列化”部分下)

只是一个旁注。坦率地说,我认为将反序列化器命名为MenuItemto 是不合逻辑的jodaDateTime

无论如何Field[T],必须从香草 BSON 类型转换为您的T. BSON 无法原生存储,请在此处MenuItem查看原生 BSON 类型

但当然主要问题是你有一个递归数据结构,所以你的“序列化器”(BsonWritable)和“反序列化器”(Field)也必须是递归的。Subset具有隐式序列化器/反序列化器List[T],但它们要求您提供这些MenuItem:递归。

为了简短起见,我将向您展示如何为更简单的“案例类”编写类似的东西。

假设我们有

case class Rec(id: Int, children: Option[List[Rec]])

那么作者可能看起来像

object Rec {
  implicit object asBson extends BsonWritable[Rec] {
    override def apply(rec: Rec) =
      Some( DBO("id" -> rec.id, "children" -> rec.children)() )
  }

在这里,当您写入rec.children“DBObject”时,BsonWriteable[Rec]正在使用它,它又需要“隐式” Field[Rec]。所以,这个序列化器是递归的。

对于解串器,以下将做

  import DocParser._

  implicit lazy val recField = Field({ case Doc(rec) => rec })
  lazy val Doc: DocParser[Rec] =
    get[Int]("id") ~ get[List[Rec]]("children").opt map {
      case id ~ children => new Rec(id, children)
    }
}

这些是相互递归的(记得使用lazy val!)

你会像这样使用它们:

val dbo = DBO("y" -> Rec(123, Some(Rec(234, None) :: Nil))) ()
val Y = DocParser.get[Rec]("y")
dbo match {
  case Y(doc) => doc
}
于 2013-05-17T07:10:06.337 回答