【问题标题】:Scala slick update table after querying with a join使用连接查询后的 Scala 光滑更新表
【发布时间】:2018-02-25 20:29:41
【问题描述】:

我想更新一个表,但需要根据某些条件选择行。以下代码编译正常,但抛出运行时异常:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[SlickException: A query for an UPDATE statement must resolve to a comprehension with a single table -- Unsupported shape: Comprehension s2, Some(Apply Function =), None, ConstArray(), None, None, None, None]]

这里是函数(目的是只允许合格用户更新):

def updateRecord(record: Record)(implicit loggedInUserId: User) = {
    val q = records.withFilter(_.id === record.id).join(companies).on(_.companyId === _.id).filter(_._2.userid === loggedInUserId)
    val recordToUpdate = q.map { case (r, c) => r }
    val action = for {
      c <- recordToUpdate.update(record)
    } yield (c)
    ... // there are other actions in the for comprehension, removed them for clarity

我认为映射的结果是记录表中的一行(不是元组),但错误似乎表明我没有更新“单个”表。

或者有没有更好的查询+更新方式?

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    是的,您似乎尝试更新这两个表。

    也许你应该尝试一下

      def updateRecord(record: Record)(implicit loggedInUserId: User): Future[Int] = {
        val recordToUpdate = records.filter(_.id === record.id)
    
        val q = recordToUpdate
          .join(companies).on(_.companyId === _.id)
          .filter(_._2.userid === loggedInUserId)
          .exists
    
        val action = for {
          c <- recordToUpdate.update(record)
    //      ...
        } yield c
    
        for {
          isLoggedIn <- db.run(q.result)
          if isLoggedIn
          c <- db.run(action)
        } yield c
    
      }
    

    你也可以试试

      def updateRecord(record: Record)(implicit loggedInUserId: User): 
            DBIOAction[Int, NoStream, Read with Write with Transactional] = {
        val recordToUpdate = records.filter(_.id === record.id)
    
        val action =
          recordToUpdate
          .join(companies).on(_.companyId === _.id)
          .filter(_._2.userid === loggedInUserId)
          .exists
          .result
    
        (for {
          isLoggedIn <- action
          if isLoggedIn
          c <- recordToUpdate.update(record)
    //    ...
        } yield c).transactionally
      }
    

    在没有NoSuchElementException: Action.withFilter failed 的情况下应该可以工作的变体。基于answer

      def updateRecord(record: Record)(implicit loggedInUserId: User): 
            DBIOAction[Int, NoStream, Read with Write with Transactional] = {
        val recordToUpdate = records.filter(_.id === record.id)
    
        val action =
          recordToUpdate
          .join(companies).on(_.companyId === _.id)
          .filter(_._2.userid === loggedInUserId)
          .exists
          .result
    
        action.flatMap {
          case true => for {
            c <- recordToUpdate.update(record)
          //    ...
          } yield c
    
          case false => DBIO.successful(0) /*DBIO.failed(new IllegalStateException)*/
        }.transactionally
      }
    

    【讨论】:

    • 谢谢,这使我朝着正确的方向前进。但是,就我而言,我还有其他后续操作,最后我以事务方式运行所有这些操作。所以我认为我需要的是一系列操作,但在这里我们在 for 理解中有 db.run()。想知道是否有办法在事务中完成所有这些操作。
    • 它工作了,现在我可以避免单独的数据库操作。但是它工作是因为“isLoggedIn
    猜你喜欢
    • 2021-07-09
    • 1970-01-01
    • 2012-12-13
    • 2017-04-23
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多