4

I'm using the play 2.1 framework for scala and the MongoDB Salat plugin.

When I update an Enumeration.Value I got an exception:

java.lang.IllegalArgumentException: can't serialize class scala.Enumeration$Val
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:270) ~[mongo-java-driver-2.11.1.jar:na]
    at org.bson.BasicBSONEncoder.putIterable(BasicBSONEncoder.java:295) ~[mongo-java-driver-2.11.1.jar:na]
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:234) ~[mongo-java-driver-2.11.1.jar:na]
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:174) ~[mongo-java-driver-2.11.1.jar:na]
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:120) ~[mongo-java-driver-2.11.1.jar:na]
    at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:27) ~[mongo-java-driver-2.11.1.jar:na]

Inserting the Enumeration.Value works fine. My case class looks like:

case class User(
    @Key("_id") id: ObjectId = new ObjectId,
    username: String,
    email: String,
    @EnumAs language: Language.Value = Language.DE,
    balance: Double,
    added: Date = new Date)

and my update code:

object UserDAO extends ModelCompanion[User, ObjectId] {

    val dao = new SalatDAO[User, ObjectId](collection = mongoCollection("users")) {}

    def update(): WriteResult = {
        UserDAO.dao.update(q = MongoDBObject("_id" -> new ObjectId(id)), o = MongoDBObject("$set" -> MongoDBObject("language" -> Language.EN))))
    }
}

Any ideas how to get that working?

EDIT:

workaround: it works if I cast the Enumeration.Value toString, but that's not how it should be...

UserDAO.dao.update(q = MongoDBObject("_id" -> new ObjectId(id)), o = MongoDBObject("$set" -> MongoDBObject("language" -> Language.EN.toString))))
4

3 回答 3

5

可以为枚举添加 BSON 编码。因此,转换是以透明的方式完成的。

这是代码

RegisterConversionHelpers()
  custom()
  def custom() {
    val transformer = new Transformer {

      def transform(o: AnyRef): AnyRef = o match {
        case e: Enumeration$Val => e.toString
        case _ => o
      }
    }
    BSON.addEncodingHook(classOf[Enumeration$Val], transformer)
  }
}
于 2014-02-09T15:39:28.217 回答
3

在编写 mongoDB 时,scala 枚举并不适合,我使用装饰器方法作为解决方法。

假设你有这个枚举:

object EmployeeType extends Enumeration {
  type EmployeeType = Value
  val Manager, Worker = Value
}

和这个 mongodb 记录:

import EmployeeType._
case class Employee(
  id: ObjectId = new ObjectId
)

在您的 mongoDB 中,存储枚举的整数索引而不是枚举本身:

case class Employee(
  id: ObjectId = new ObjectId,
  employeeTypeIndex: Integer = 0
){
  def employeeType = EmployeeType(employeeTypeIndex); /* getter */
  def employeeType_=(v : EmployeeType ) = { employeeTypeIndex= v.id} /* setter */
}

额外的方法实现了员工类型枚举的 getter 和 setter。

于 2013-11-21T15:58:27.113 回答
1

Salat 仅在您使用刨丝器对模型对象进行序列化时才起作用,而不是在您自己使用 MongoDB 对象进行查询时。mongo 驱动程序 api 对 @EnumAs 注释一无所知。(除此之外,即使您可以为此使用 salat,它如何知道您指的是通用键-> 值 MongoDBObject 中的 User.language?)

所以你必须像你在解决方法中描述的那样做。当您想要进行查询时,您自己提供枚举的“值”。

于 2013-08-04T11:00:39.670 回答