我们想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中编写它,以便我们可以通过一次数据库调用更新记录中的任意数量的字段?
为什么不在构建更新查询之前进行模式匹配?
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)
我最好的猜测是运行一个简单的 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)