尝试返回插入的行时无法插入平滑插入

时间:2019-06-05 10:35:59

标签: scala playframework slick

我的目标是在插入时检索Board实体。如果该实体存在,那么我只想返回现有对象(与add方法的参数一致)。否则,我想返回数据库中插入的新行。

我正在将Play 2.7与Slick 3.2和MySQL 5.7结合使用。

该实现基于this答案,远比见识深刻。

也来自Essential Slick

  

exec(消息返回消息+ =     Message(“ Dave”,“所以...我们现在要做什么?”)

DAO代码

@Singleton
class SlickDao @Inject()(db: Database,implicit val playDefaultContext: ExecutionContext) extends MyDao {


    override def add(board: Board): Future[Board] = {
        val insert = Boards
                .filter(b => b.id === board.id && ).exists.result.flatMap { exists =>
            if (!exists) Boards returning Boards += board
            else DBIO.successful(board) // no-op - return specified board
        }.transactionally

        db.run(insert)
    }

编辑:还尝试将+=部分替换为

Boards returning Boards.map(_.id) into { (b, boardId) => sb.copy(id = boardId) } += board

这也不起作用

表定义如下:

object Board {

    val Boards: TableQuery[BoardTable] = TableQuery[BoardTable]

    class BoardTable(tag: Tag) extends Table[BoardRow](tag, "BOARDS") {

        // columns
        def id = column[String]("ID", O.Length(128))
        def x = column[String]("X")
        def y = column[Option[Int]]("Y")

        // foreign key definitions
        .....
        // primary key definitions
        def pk = primaryKey("PK_BOARDS", (id,y))


        // default projection
        def * = (boardId, x, y).mapTo[BoardRow]

    }
}

我希望表中会有一个新行,但是尽管exists查询已执行

select exists(select `ID`, `X`, `Y`
              from `BOARDS`
              where ((`ID` = '92f10c23-2087-409a-9c4f-eb2d4d6c841f'));

结果为false,没有插入。

数据库中没有任何日志记录可以接收到任何插入语句(我指的是general_log文件)

1 个答案:

答案 0 :(得分:0)

因此,首先,查询执行的问题是对DAO生产的期货的处理不当。我正在将insert语句分配给将来,但是这个将来从未提交给执行上下文。更糟糕的是,我没有在问题描述中提及它。

但是,在实际解决此问题后,我可以在应用程序的日志中看到实际的错误。堆栈跟踪如下:

slick.SlickException: This DBMS allows only a single column to be returned from an INSERT, and that column must be an AutoInc column.
   at slick.jdbc.JdbcStatementBuilderComponent$JdbcCompiledInsert.buildReturnColumns(JdbcStatementBuilderComponent.scala:67)
   at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.x$17$lzycompute(JdbcActionComponent.scala:659)
   at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.x$17(JdbcActionComponent.scala:659)
   at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.keyColumns$lzycompute(JdbcActionComponent.scala:659)
   at slick.jdbc.JdbcActionComponent$ReturningInsertActionComposerImpl.keyColumns(JdbcActionComponent.scala:659)

所以这是MySQL的核心。为了使插入后的检索成为可能,我必须重新设计架构。重新设计包括引入专用主键(与业务逻辑完全无关),该主键也是堆栈跟踪规定的AutoInc列。

最后,解决方案变得过于复杂,因此决定使用add方法的实际参数来返回是否实际插入成功。因此,add方法的实现最终是这样的

override def add(board: Board): Future[Board] = {
        db.run(Boards.insertOrUpdate(board).map(_ => board))
    }

控制器中有一些适当的Future错误处理正在调用基础存储库。

如果您很幸运并且没有在Slick上使用MySQL,我想您可能可以在没有专用AutoInc主键的情况下完成此操作。如果不是这样,我想这是一条单向路。