import com.escalatesoft.subcut.inject._
import com.mongodb.casbah.Imports._
import com.novus.salat._
import com.novus.salat.global._
import com.novus.salat.dao._
case class User(_id: ObjectId = new ObjectId, email: String, password: String)
class UserDAO(coll: MongoCollection = DatabaseClient.getCollection("users")) extends SalatDAO[User, ObjectId](
collection = coll
)
class UserRepository(implicit val bindingModule: BindingModule) extends Injectable {
val userDAO = injectOptional [UserDAO] getOrElse {new UserDAO}
def createUser (email: String, password: String):Option[ObjectId] = {
val newUser = User(email = email, password = password)
val createdUser = userDAO.insert(newUser)
createdUser
}
}
基本上当插入新用户时,它返回Some(“新用户的ObjectId”),这正是我期望它做的。但是,当我在电子邮件上放置索引时,我得到重复的密钥错误。我想要的不是获取重复键错误,而是获取None选项,就像我从集合中读取并且没有匹配文档时那样。
当MongoDB返回重复键错误时,如何获得None选项?
或者我应该如何处理这个错误,我回来了?
答案 0 :(得分:2)
如果您要求电子邮件是唯一的,那么您的insert方法应该捕获并处理DuplicateKeyError(并非每个可能的错误 - 如果写入完全失败怎么办?您不想知道吗?)或避免这种情况完全通过检查首先是否存在唯一键来判断错误。
我认为更好的方法不是让错误变得沉默,而是首先使用您的唯一密钥“电子邮件”搜索集合,如果您发现了某些内容,请更新现有用户或忽略重复用户 - 无论您是用例是。
其次,如果您使用它进行单元测试,那么您的单元测试应该设置并拆除测试集合,使得每个测试用例都以已知的外部资源(MongoDB集合)运行状态。
以下是Salat如何使用specs2执行此操作的示例: https://github.com/novus/salat/blob/master/salat-core/src/test/scala/com/novus/salat/test/dao/SalatDAOSpec.scala
答案 1 :(得分:1)
我会给你两个问题的答案。第一个需要稍微改变你的方法。如果Salat DAO功能可能会在插入时抛出异常,您可能需要考虑更改createUser
函数以返回Try[Option[ObjectId]]
而改写它,如下所示:
def createUser (email: String, password: String):Try[Option[ObjectId]] = {
val newUser = User(email = email, password = password)
Try(userDAO.insert(newUser))
}
现在调用者知道结果将是以下三种情况之一:Success(Some(objectId))
,Success(None)
(不确定何时会发生但是因为它是Option
,你必须能够处理它)或Failure
包装一些异常。这样你甚至可以对Failure
中的异常进行模式匹配,以确保它是重复键上的一个,并相应地采取行动,而不是仅仅吞下任何异常,并假设它必须是由于重复键。
现在,如果你真的想要任何失败的无,你可以像这样重新定义createUser
:
def createUser (email: String, password: String):Option[ObjectId] = {
val newUser = User(email = email, password = password)
Try(userDAO.insert(newUser)).toOption.flatten
}
这会吞下insert
的任何例外并返回None
。