带有多个PK insertOrUpdate()的Scala的Slick抛出异常错误:输入结束时出现语法错误

Kon*_*nin 7 postgresql scala upsert composite-primary-key slick

我正在使用Scala的Slick和PostgreSQL.我和单PK的桌子一起工作得很好.现在我需要使用具有多个PK的表:

case class Report(f1: DateTime,
    f2: String,
    f3: Double)

class Reports(tag: Tag) extends Table[Report](tag, "Reports") {
    def f1 = column[DateTime]("f1")
    def f2 = column[String]("f2")
    def f3 = column[Double]("f3")

    def * = (f1, f2, f3) <> (Report.tupled, Report.unapply)
    def pk = primaryKey("pk_report", (f1, f2))
}

val reports = TableQuery[Reports]
Run Code Online (Sandbox Code Playgroud)

当我有空桌并使用reports.insert(report)它很好.但是,当我使用reports.insertOrUpdate(report)我接收和例外时:

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: syntax error at end of input
  Position: 76
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:500)
    at ....
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?怎么解决?

提前致谢.


PS.我尝试了解决方法 - 尝试通过以下方式实现"if exist update else insert"逻辑:

  val len = reports.withFilter(_.f1 === report.f1).withFilter(_.f2 === report.f2).length.run.toInt
                    if(len == 1) {
                        println("Update: " + report)
                        reports.update(report)
                    } else {
                        println("Insert: " + report)
                        reports.insert(report)
                    }
Run Code Online (Sandbox Code Playgroud)

但我仍然在更新时遇到异常:

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_report"
  Detail: Key ("f1", f2)=(2014-01-31 04:00:00, addon_io.aha.connect) already exists.
Run Code Online (Sandbox Code Playgroud)

sca*_*1sk 7

关于你的初始问题,在具有复合键的表上的insertOrUpdate在Slick中被破坏(至少使用PGSql),因此错误不在您身边.请参阅错误报告,例如:https://github.com/slick/slick/issues/966

所以你必须设计一个解决方法,但是"upsert"操作很容易出现竞争条件,并且很难正确设计,因为PostgreSQL没有提供本机功能来执行此操作.参见例如http://www.depesz.com/2012/06/10/why-is-upsert-so-complicated/

无论如何,执行不太容易出现竞争条件的操作的另一种方法是首先更新(如果该行不存在则不会执行任何操作),然后执行"插入选择"查询,该查询仅插入如果该行不存在.这就是Wlick Slick将使用单个PK在PostgreSQL上执行insertOrUpdate操作.但是,"插入选择"无法直接使用Slick完成,您将不得不回退直接SQL.


Vik*_*dya 3

第二部分你有

val len = reports.withFilter(_.f1 === report.f1).withFilter(_.f2 === report.f2).length.run.toInt
                if(len == 1) {
                    println("Update: " + report)
                    reports.update(report)
                } else {
                    println("Insert: " + report)
                    reports.insert(report)
                }
Run Code Online (Sandbox Code Playgroud)

改变reports.update(report)

reports.filter(_.id === report.id).update(report)

实际上你可以只打一个filter电话(代替你的第一个电话withFilter