Scala,Play - 尝试实现存储库时json类型转换的问题

时间:2013-09-22 13:10:48

标签: json scala playframework playframework-2.1

我是Scala新手,他第一次尝试使用Scala和Play 2.1创建一个webapp。

我正在尝试创建一个UserRepository类,它将使用响应式Mongo和响应式Mongo Play插件作为MongoDB的User对象的存储库。

这是我不明白的事情。考虑这个存储库类:

@Singleton
class UserRepository @Inject() (db: DB) {
    import scala.concurrent.ExecutionContext.Implicits.global

    val collection:JSONCollection = db.collection("users")

    def find(terms: (String, JsValueWrapper)*): Future[List[User]] = {
      find(Json.obj(terms:_*))
    }

    //Problematic method that sometimes works sometimes not
    def findOne(terms: (String, JsValueWrapper)*): Future[Option[User]] = {
       findOne(Json.obj(terms:_*))
    }

    def find(selector: JsObject): Future[List[User]] = {
       collection.find(selector).cursor[User].toList()
    }

    def findOne(selector: JsObject): Future[Option[User]] = {
       collection.find(selector).one[User]
    }

    def findByEmailAndPassword(email: String, password: String): Future[Option[User]] = {
       //problematic method works fine here
       findOne("email" -> email, "password" -> password)
    }

} 

我想创建一个使用vararg元组来描述Mongo选择器对象的find方法。 我在存储库类本身的findByEmailAndPassword方法中使用它,它工作正常。

更新

调用findOne在密钥中不起作用 - >值形式,如果我只提供一个元组(无论从哪里调用)。 这有效:

findOne(("email", "example@test.com"))
findOne("email" -> "example@test.com", "password" -> "foo")
val term: (String, JsValueWrapper) = "email" ->  "example@test.com"
findOne(term)

这不起作用:

findOne("email" -> "example@test.com")

为什么?

更新2:

我已经将更新的方法看起来像这样(所以我可以在存储库类之外提供Writes和Reads对象):

def findOne[V](terms: (String, V)*)(implicit reads: Reads[T], writes: Writes[V]): Future[Option[T]] = {
  val objMap = terms.map(entry => (entry._1, Json.toJsFieldJsValueWrapper(entry._2)))
  findOne(Json.obj(objMap:_*))
}

此更新后,不再出现错误。虽然我仍然不明白为什么它首先不起作用。

原始问题:

但是当我在这样的控制器中使用存储库时:

@Singleton
class TestController @Inject() (val userRepository: UserRepository) extends Controller {

  def testFind = Action { implicit request =>
    Async {
      //This call to findOne doesn't work
      val query = userRepository.findOne("email" -> "test@example.com")

      //This call works fine:
      //val query = userRepository.findOne(Json.obj("email" -> "test@example.com"))
      query.map(
        userOption => userOption.map(u => Ok("Found user: " + u.toString)).getOrElse(Ok("No user found.")))
      }
    }
}

当我在Controller类中调用userRepository.findOne("email" -> "test@example.com")时,它不起作用。但是当我对存储库类中的相同方法进行类似的调用时它会工作 - 它可以正常工作(例如,findByEmailAndPassword工作正常)。从控制器调用时得到的错误是:

Overloaded method value [findOne] cannot be applied to ((String, String))

我认为它是隐式转换问题,但我在控制器类中的所有导入都与在存储库类中一样,但在Controller中使用方法时,String不会转换为JsValueWrapper。

任何帮助将不胜感激,欢迎声明findOne(terms *)方法的替代解决方案,谢谢。

1 个答案:

答案 0 :(得分:0)

也许你应该另外定义另一个内部委托给findOne的findOne(term:(String,JsValueWrapper))方法(术语:(String,JsValueWrapper)*)?