当mongodb给出错误时,如何从salatDAO获取无选项

时间:2013-07-10 07:31:18

标签: mongodb scala scalatra salat

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选项?

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

2 个答案:

答案 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