我是 Scala 新手,第一次尝试使用 Scala 和 Play 2.1 创建 web 应用程序。
我正在尝试使用响应式 Mongo 和响应式 Mongo Play 插件创建一个 UserRepository 类,它将作为用户对象到 MongoDB 的存储库。
这是我不明白的事情。考虑这个存储库类:
@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)
}
}
我想创建一个使用可变参数元组来描述 Mongo 选择器对象的 find 方法。我在存储库类本身的 findByEmailAndPassword 方法中使用它,它工作正常。
更新:
如果我只提供一个元组(不管它是从哪里调用的),调用 findOne 就不能以 key -> value 的形式工作。这有效:
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.")))
}
}
}
当我调用userRepository.findOne("email" -> "test@example.com")
Controller 类时,它不起作用。但是当我在存储库类中对相同的方法进行类似的调用时它确实如此——它工作正常(例如 findByEmailAndPassword 工作正常)。从控制器调用时我得到的错误是:
Overloaded method value [findOne] cannot be applied to ((String, String))
我认为这是隐式转换问题,但控制器类中的导入与存储库类中的导入确实相同,但在控制器中使用方法时,String 不会转换为 JsValueWrapper。
任何帮助将不胜感激,也欢迎声明 findOne(terms*) 方法的替代解决方案,谢谢。