0
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 of new user") 这正是我期望它做的。但是,当我在电子邮件上放置索引时,我会收到重复键错误。我想要的不是得到重复键错误,而是得到 None 选项,就像我从集合中读取并且没有匹配的文档时所做的那样。

当 MongoDB 返回重复键错误时,如何获得 None 选项?

或者我应该如何处理我回来的这个错误?

4

2 回答 2

2

如果您要求电子邮件是唯一的,那么您的插入方法应该捕获并仅处理 DuplicateKeyError (不是每个可能的错误 - 如果写入完全失败怎么办?您不想知道吗?)或完全避免此错误首先检查唯一键是否存在。

我认为更好的方法不是消除错误,而是首先使用您的唯一键“电子邮件”搜索集合,如果您发现某些内容,请更新现有用户或忽略重复用户 - 无论您的用例是什么.

其次,如果您使用它进行单元测试,那么您的单元测试应该以这样一种方式设置和拆除测试集合,即您的每个测试用例都在外部资源(MongoDB 集合)处于已知状态时运行。

这是 Salat 如何使用 specs2 执行此操作的示例: https ://github.com/novus/salat/blob/master/salat-core/src/test/scala/com/novus/salat/test/dao/SalatDAOSpec.scala

于 2013-07-10T13:06:23.583 回答
1

这个问题我给你两个答案。第一个需要稍微改变你的方法。如果 Salat DAO 功能可能在插入时抛出异常,您可能需要考虑更改createUser函数以返回 aTry[Option[ObjectId]]并像这样重新编写它:

def createUser (email: String, password: String):Try[Option[ObjectId]] = {
  val newUser = User(email = email, password = password)
  Try(userDAO.insert(newUser))  
}

现在调用者知道结果将是以下三件事之一: a Success(Some(objectId)), a Success(None)(不确定何时会发生,但由于它是 a 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.

于 2013-07-10T12:23:07.420 回答