问题 SLICK 3.0 - 多个查询相互依赖 - db.run(action)


我是Slick 3的新手,到目前为止我已经理解db.run是异步调用。返回Future后运行.map或.flatMap。

我的代码中的问题是所有子查询都不起作用(嵌套db.run)。

从概念上讲,我没有得到什么?这样的代码是否有效,如下所示?基本上在第一个查询的.map中我根据第一个查询执行一些操作。

我到处都看到了 for yield与yield,这是唯一的出路吗?我的代码中的问题是否与返回的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)
            }
        }
    }
})

3276
2017-07-17 08:38


起源

嗨@ user1237981下面的答案有帮助吗?还是不清楚?还是我错过了你需要的点? - Richard Dallaway
谢谢你,RIchard,它立即工作。我正在度假,不能马上回复。 - user1237981
大!谢谢。 - Richard Dallaway


答案:


我的代码中的问题是所有子查询都不起作用(嵌套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


14
2017-07-18 10:06



嗨理查德,谢谢你的回复。它运作得很好。我只需要练习这些for循环。另外,我已经调查了你的博客并获得了灵感。做得太好了。再次感谢。 - user1237981