SLICK 3.0 - несколько запросов в зависимости друг от друга - db.run(действие)

Я новичок в Slick 3 и до сих пор я понял, что db.run - это асинхронный вызов..map или.flatMap запускается после возвращения Future.

Проблема в моем коде ниже состоит в том, что все подзапросы не работают (вложенный db.run).

Концептуально говоря, что я не получаю? Допустимо ли делать такой код, как показано ниже? в основном в.map первого запроса я делаю некоторые действия в зависимости от первого запроса.

Я вижу повсюду циклы с выходом, это единственный путь? Связана ли проблема в моем коде с возвращенным значением Future?

val enterprises = TableQuery[Enterprise]
val salaries = TableQuery[Salary]

//Check if entered enterprise exists 
val enterpriseQS = enterprises.filter(p => p.name.toUpperCase.trim === salaryItem.enterpriseName.toUpperCase.trim).result

val result=db.run(enterpriseQS.headOption).map(_ match 
{
    case Some(n) => {
      //if an enterprise exists use the ID from enterprise (n.id) when adding a record to salary table
      val addSalary1 = salaries += new SalaryRow(0, n.id, salaryItem.worker)
      db.run(addSalary1)
    }
    case None =>  {
        //if an enterprise with salaryItem.enterpriseName doesn't exist, a new enterprise is inserted in DB
        val enterpriseId = (enterprises returning enterprises.map(_.id)) += EnterpriseRow(0, salaryItem.enterpriseName)
        db.run(enterpriseId).map{
            e => {
                val salaryAdd2 = salaries += new SalaryRow(0, e, salaryItem.worker)
                db.run(salaryAdd2)
            }
        }
    }
})

1 ответ

Решение

Проблема в моем коде ниже заключается в том, что все подзапросы не работают (вложенный db.run)

Я подозреваю, что вы в конечном итоге с вложенными Future[R] Результаты. Я не исследовал это все же. Так как...

Концептуально говоря, что я не получаю?

То, как я бы занялся этим, это посмотреть на объединение DBIO[R], Это может быть концепция, которая помогает.

То, что вы делаете, это пытаетесь выполнить каждое действие (запрос, вставка...) индивидуально. Вместо этого объедините отдельные действия в одно действие и запустите его.

Я бы переписал основную логику так:

  val action: DBIO[Int] = for {
    existingEnterprise <- enterpriseQS.headOption
    rowsAffected       <- existingEnterprise match {
      case Some(n) => salaries += new SalaryRow(0, n.id, salaryItem.worker)
      case None    => createNewEnterprise(salaryItem)
    }
  } yield rowsAffected

Для None В этом случае я бы создал вспомогательный метод:

  def createNewEnterprise(salaryItem: SalaryItem): DBIO[Int] = for {
    eId          <- (enterprises returning enterprises.map(_.id)) += EnterpriseRow(0, salaryItem.enterpriseName)
    rowsAffected <- salaries += new SalaryRow(0, eId, salaryItem.worker)
  } yield rowsAffected

Наконец, мы можем запустить это:

  val future: Future[Int] = db.run(action)
  // or db.run(action.transactionally)    

  val result = Await.result(future, 2 seconds)

  println(s"Result of action is: $result")

Вторая половина поста в блоге, который я написал, больше говорит об этом.

Код, который я использовал: https://github.com/d6y/so-31471590

Другие вопросы по тегам