我的目标是在插入时检索Board
实体。如果该实体存在,那么我只想返回现有对象(与add方法的参数一致)。否则,我想返回数据库中插入的新行。
我正在将Play 2.7与Slick 3.2和MySQL 5.7结合使用。
该实现基于this答案,远比见识深刻。
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
文件)
答案 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主键的情况下完成此操作。如果不是这样,我想这是一条单向路。