如何在Scala Slick中运行补丁/部分数据库UPDATE?

Ric*_*ell 17 scala slick

我们想UPDATE用Slick(3.0.0)运行补丁/部分,这样我们只修改记录中的一些字段.确切地说,哪些字段将在运行时才会被更新.

例如,对于REST PATCH请求.

目前我们运行SELECT第一个获取原始记录然后运行,UPDATE但在单个SQL语句中执行此操作会更好.

像这样的东西:

def patchPerson(name: Option[String], age: Option[Int]) = {
   people.filter(_.name === "M Odersky")
       .map(p => 
           (name, age) match {
              case (Some(_), Some(_)) => (p.name, p.age)
              case (Some(_), None)    => (p.name)
              case (None   , Some(_)) => (p.age)
           }
       )
       .update(
           (name, age) match {
              case (Some(_), Some(_)) => (name.get, age.get)
              case (Some(_), None)    => (name.get)
              case (None   , Some(_)) => (age.get)
           }
       )
}
Run Code Online (Sandbox Code Playgroud)

(请忽略这里丑陋的代码)

上面的代码不能编译,并显示以下错误消息:

找不到匹配的形状.Slick不知道如何映射给定的类型.可能的原因:表[T]中的T与您的*投影不匹配.或者在查询中使用不受支持的类型(例如scala列表).所需级别:slick.lifted.FlatShapeLevel源类型:对象未包装类型:T包装类型:G

和:

没有足够的方法映射参数:(隐式形状:slick.lifted.Shape [_ <:slick.lifted.FlatShapeLevel,Object,T,G])slick.lifted.Query [G,T,Seq].未指定的值参数形状.

我假设这是因为Slick期望元组长度和类型匹配filter和update函数的结果.

我们已经尝试使用Slick 异构列表类,但这似乎也期望长度和类型匹配.

有没有办法在Slick中编写它,以便我们可以通过一次数据库调用更新记录中的任意数量的字段?

thi*_*row 5

为什么不在构建更新查询之前进行模式匹配?

def patchPerson(name: Option[String], age: Option[Int]) = {
   val query = people.filter(_.name === "M Odersky")
   (name, age) match {
     case (Some(name), Some(age)) =>
       query.map(p => (p.name, p.age)).update(name, age)
     case (Some(name), None) =>
       query.map(p => p.name).update(name)
     case (None, Some(age)) =>
       query.map(p => p.age).update(age)
   }
}
Run Code Online (Sandbox Code Playgroud)


ped*_*o91 1

我最好的猜测是运行一个简单的 SQL 查询

即使 SQL 查询有 2 个部分,关系数据库管理系统(postgresql、mysql 等)也能够在幕后调整查询。

我不确定在这种情况下 Slick 是否能够优化,但在某些情况下它也会自行优化查询。

典型更新:

def updateRecord(id: Long, field1: Int) = {
    db.withSession {
      self.filter(_.id === id).map(_.field1).update(field1)
    }
}
Run Code Online (Sandbox Code Playgroud)

进行您的更新类型需要像您一样更多的逻辑。如果您只在运行时知道要更改哪些字段,则不要认为可以简化。但是您可以强制更新,使用记录上字段的现有值作为后备(可能会导致数据库上的更新比应有的更多)

def updateRecord(id: Long, field1: Option[Int], field2: Option[Int]) = {
    db.withSession {
        self.filter(_.id === id).map(_.field1, _.field2).update(field1.getOrElse(existingValue1), field2.getOrElse(existingValue2)) 
    }
}
Run Code Online (Sandbox Code Playgroud)