Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何捕获重复键值冲突的光滑postgres异常_Scala_Playframework_Slick - Fatal编程技术网

Scala 如何捕获重复键值冲突的光滑postgres异常

Scala 如何捕获重复键值冲突的光滑postgres异常,scala,playframework,slick,Scala,Playframework,Slick,我的表在我的postgresql数据库中的一对列上有一个唯一的索引 我想知道如何在插入时捕获重复密钥异常: def save(user: User)(implicit session: Session): User = { val newId = (users returning users.map(_id) += user user.copy(id = newId) } 我的日志显示此异常: Execution exception[[PSQLException: ERROR: dup

我的表在我的postgresql数据库中的一对列上有一个唯一的索引

我想知道如何在插入时捕获重复密钥异常:

def save(user: User)(implicit session: Session): User = {
  val newId = (users returning users.map(_id) += user
  user.copy(id = newId)
}
我的日志显示此异常:

Execution exception[[PSQLException: ERROR: duplicate key value violates unique constraint "...."

我在scala中也没有太多使用异常。

您的
save
方法可能会返回与
User
不同的结果,以指示失败的可能性。如果将抛出的唯一异常是unique key,并且您实际上只关心成功或失败(而不关心失败的类型),那么一种方法是返回
选项[User]

您可以使用一个简单的
try/catch
块,将成功保存映射到
Some[User]
psqleexception
None

def save(user: User)(implicit session: Session): Option[User] = {
  try {
    val newId = (users returning users.map(_id) += user
    Some(user.copy(id = newId))
  } catch {
      case PSQLException => None
  }
}
就个人而言,我不会这样做,因为
try/catch
并不是真正惯用的Scala,您的错误类型被丢弃。下一个选项是使用
scala.util.Try

def save(user: User)(implicit session: Session): Try[User] = Try {
  val newId = (users returning users.map(_id) += user
  user.copy(id = newId)
}
这里的代码更简单。如果
Try
的主体成功,则
save
将返回
Success[User]
,否则将返回包装在
Failure
中的异常。这将允许您使用
Try
执行许多操作

def save(user: User)(implicit session: Session): Try[User] = Try {
  val newId = (users returning users.map(_id) += user
  user.copy(id = newId)
}
您可以选择以下模式匹配:

save(user) match {
   case Success(user) => Ok(user)
   case Failure(t: PSQLException) if(e.getSQLState == "23505") => InternalServerError("Some sort of unique key violation..")
   case Failure(t: PSQLException) => InternalServerError("Some sort of psql error..")
   case Failure(_) => InternalServerError("Something else happened.. it was bad..")
}
您可以像
选项那样使用它:

save(user) map { user =>
   Ok(user)
} getOrElse {
   InternalServerError("Something terrible happened..")
}
您可以一次将多个组件组合在一起,并在第一次失败时停止:

(for {
   u1 <- save(user1)
   u2 <- save(user2)
   u3 <- save(user3)
} yield {
  (u1, u2, u3)
}) match {
   case Success((u1, u2, u3)) => Ok(...)
   case Failure(...) => ...
}
(用于{

u1在Slick 3.x中,您可以使用asTry

def save(user: User)(implicit session: Session): Try[User] = Try {
  val newId = (users returning users.map(_id) += user
  user.copy(id = newId)
}
我使用的是MySQL,但是相同的代码可以用于PostgreSQL,只是例外情况不同

import scala.util.Try
import scala.util.Success
import scala.util.Failure

db.run(myAction.asTry).map {result =>  

  result match {

    case Success(res) => 
      println("success")
      // ...

    case Failure(e: MySQLIntegrityConstraintViolationException) => {
      //code: 1062, status: 23000, e: Duplicate entry 'foo' for key 'name'
      println(s"MySQLIntegrityConstraintViolationException, code: ${e.getErrorCode}, sql status: ${e.getSQLState}, message: ${e.getMessage}")
      // ...
    }

    case Failure(e) => {
      println(s"Exception in insertOrUpdateListItem, ${e.getMessage}")
      // ...
    }
  }
}

注意:也可以映射操作(
myAction.asTry.map…
)而不是
db.run

哇,非常好的信息,谢谢。为了澄清一下,要挑出一个“重复键”,我是否必须解析从消息返回的字符串消息,以确定它是否是重复键?(与其他psqlexeptions相反)。要么这样,要么通过匹配SQL状态。我不使用postgres,所以我不确定这是否100%准确(mysql使用错误代码),但例如
case e e:psqleexception if(e.getSQLState==“23505”)=>…
查看此页面:匹配Try to scalaz析取的输出,您可以很好地对方法的契约进行建模。这是一个很好的API,很容易与新手一起使用。问题:隐式会话是什么?类
DBResult
DBStatus
是什么?我在光滑的scalado中没有看到它们这些是我自己的cla我还为我的所有数据库结果使用带有自定义状态代码的结果包装器。我将删除它们以避免混淆。