I have insert method like this (weight is index)
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))))
}
}
and I call it 2 time
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)
}
and it return exception(Unique index).
How to fix this and I don't use for-comprehension or insert in first onComplete. Just call it 2 time.
Thank you.
That is a common mistake - converting to
Future
to early (in other words callingdb.run(...)
to early).What you need to do is to remove this method as it (maybe a little unintuitively) brings more harm than good:
Rule of thumb is basically that you usually would like to strictly control you actual database interactions (and transactional boundaries) so I would advice against any kind of
implicit
s in this area. After all it's one of the driving ideas behind this library -Slick
tries to be very explicit in your interactions between application and db (contrary to classic ORMs - where using accessor might have actually fired lazy call to db or setting a value through mutator might resulted in actual database update).Then you need to change the return type to this (changed
Future
toDBIO
):and than you do this:
Basically the thing is: as soon as you convert
DBIO
toFuture
you loose capability of bundling actions into single transaction. So you basically do everything with use of different transformations of DBIO (usual stuff:map
,flatMap
,seq
etc) and only as the very last step you firedb.run(yourComposedDbio.transactionally)
.EDIT: Here is some more information about handling transactions and
DBIO
composition from the presentation I gave couple of weeks ago. Relevant slide: http://slides.com/pdolega/slick-101#/85 (and further).Also there is a great workshop run by Dave Gurnell where he talks about this at around: 01:05:00 (link here: https://vimeo.com/148074461 )