Построить динамический запрос UPDATE в Slick 3
Я ищу способ создания запроса UPDATE для нескольких столбцов, которые известны только во время выполнения.
Например, учитывая List[(String, Int)]
Как бы я пошел о создании запроса в виде UPDATE <table> SET k1=v1, k2=v2, kn=vn
для всех пар ключ / значение в списке?
Я обнаружил, что, учитывая одну пару ключ / значение, простой SQL-запрос может быть построен как sqlu"UPDATE <table> SET #$key=$value
(где ключ из доверенного источника, чтобы избежать внедрения), но мне не удалось обобщить это в список обновлений без выполнения запроса для каждого из них.
Это возможно?
1 ответ
Это один из способов сделать это. Я создаю определение таблицы T здесь с именами таблиц и столбцов (TableDesc) в качестве неявных аргументов. Я бы подумал, что можно установить их явно, но я не смог его найти. Для примера экземпляры запроса создания в таблицу, aTable и bTable. Затем я вставляю и выбираю некоторые значения и в конце я обновляю значение в bTable.
import slick.driver.H2Driver.api._
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.util.{Failure, Success}
val db = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1", "sa", "", null, "org.h2.Driver")
case class TableDesc(tableName: String, intColumnName: String, stringColumnName: String)
class T(tag: Tag)(implicit tableDesc: TableDesc) extends Table[(String, Int)](tag, tableDesc.tableName) {
def stringColumn = column[String](tableDesc.intColumnName)
def intColumn = column[Int](tableDesc.stringColumnName)
def * = (stringColumn, intColumn)
}
val aTable = {
implicit val tableDesc = TableDesc("TABLE_A", "sa", "ia")
TableQuery[T]
}
val bTable = {
implicit val tableDesc = TableDesc("TABLE_B", "sb", "ib")
TableQuery[T]
}
val future = for {
_ <- db.run(aTable.schema.create)
_ <- db.run(aTable += ("Hi", 1))
resultA <- db.run(aTable.result)
_ <- db.run(bTable.schema.create)
_ <- db.run(bTable ++= Seq(("Test1", 1), ("Test2", 2)))
_ <- db.run(bTable.filter(_.stringColumn === "Test1").map(_.intColumn).update(3))
resultB <- db.run(bTable.result)
} yield (resultA, resultB)
Await.result(future, Duration.Inf)
future.onComplete {
case Success(a) => println(s"OK $a")
case Failure(f) => println(s"DOH $f")
}
Thread.sleep(500)
В конце я получил инструкцию сна, чтобы утверждать, что Future.onComplete получает время для завершения до завершения приложения. Есть ли другой путь?