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返回重复键错误时,如何获得"无"选项?
或者我应该如何处理我返回的此错误?
如果你要求电子邮件是唯一的,那么你的插入方法应该只捕获并处理DuplicateKeyError(不是每一个可以想象的错误 - 如果写入完全失败怎么办? 你不想知道吗?或者通过检查唯一键是否存在来完全避免此错误。
我认为更好的方法不是静音错误,而是首先使用唯一键"电子邮件"搜索集合,如果发现某些内容,请更新现有用户或忽略重复用户 - 无论您的用例是什么。
其次,如果您将其用于单元测试,那么您的单元测试应该设置和拆除测试集合,以便每个测试用例都与已知状态下的外部资源(MongoDB 集合(一起运行。
以下是 Salat 如何使用 specs2 执行此操作的示例:https://github.com/novus/salat/blob/master/salat-core/src/test/scala/com/novus/salat/test/dao/SalatDAOSpec.scala
我会给你两个答案。 第一个需要稍微改变你的方法。 如果 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
中的异常进行模式匹配,以确保它是在重复键上抛出的异常并采取相应的行动,而不是只是吞下任何异常并假设它一定是由于重复键引起的。
现在,如果您真的想要任何故障的 None,您可以像这样重新定义createUser
:
def createUser (email: String, password: String):Option[ObjectId] = {
val newUser = User(email = email, password = password)
Try(userDAO.insert(newUser)).toOption.flatten
}
这将吞下insert
中的任何异常并返回None
。