我有这样的插入方法(权重是索引)
implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
db.run(action)
}
def insert(newCategory: CategoryExtractor): Future[Either[String, CategoryResponse]] = {
category.map(_.weight).max.result.flatMap {
case Some(weight) =>
val temp = newCategory.copy(weight = weight+1)
(category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
case None =>
val temp = newCategory.copy(weight = 1)
(category += temp).andThen(DBIO.successful(Right(toCategoryExtractor(temp))))
}
}
我称之为2次
insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) onComplete {
case Success(data) => println(data)
}
insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) onComplete {
case Success(data) => println(data)
}
并返回异常(唯一索引)。
如何解决这个问题,我不首先使用for-comprehension或insert in onComplete。只需打两次电话。
谢谢。
答案 0 :(得分:5)
这是一个常见的错误 - 转换为Future
到早期(换句话说,将db.run(...)
调用到早期)。
你需要做的是删除这种方法,因为它(可能有点不直观)带来的弊大于利:
implicit def run[A](action: DBIOAction[A, NoStream, _ <: slick.dbio.Effect]): Future[A] = {
db.run(action)
}
经验法则基本上是您通常希望严格控制您实际的数据库交互(以及事务边界),因此我会建议不要在此区域中使用任何类型的implicit
。毕竟这是这个库背后的驱动思想之一 - Slick
试图在应用程序和数据库之间的交互中非常明确(与经典的ORM相反 - 使用访问器可能实际上已经激活了对数据库的懒惰调用或设置了值通过mutator可能会导致实际的数据库更新。
然后您需要将返回类型更改为此(将Future
更改为DBIO
):
def insert(newCategory: CategoryExtractor): DBIO[Either[String, CategoryResponse]] = {
...
}
而不是你这样做:
val firstInsert = insert(CategoryExtractor("1", "name", "scala every where", 0, 0, 0, None)) map {
data => println(data)
}
val secondInsert = insert(CategoryExtractor("2", "name", "haskell every where", 0, 0, 0, None)) map {
data => println(data)
}
db.run(DBIO.seq(firstInsert, secondInsert).transactionally))
基本上就是:只要您将DBIO
转换为Future
,就会失去将动作捆绑到单个交易中的能力。所以你基本上都会使用不同的东西来做所有事情DBIO的转换(通常的内容:map
,flatMap
,seq
等),并且只作为解雇db.run(yourComposedDbio.transactionally)
的最后一步。
编辑:
以下是有关处理交易和DBIO
组合的更多信息,这些信息来自我几周前的演示文稿。相关幻灯片:http://slides.com/pdolega/slick-101#/85(以及更多)。
另外还有一个由Dave Gurnell主持的精彩研讨会,他在附近谈论这个:01:05:00(链接在这里:https://vimeo.com/148074461)