ZIO-Quill 条件更新实现:如何按用户值更新表行?
仅更新Scala样例类中非None字段的数据库实现
假设使用Slick(Scala主流数据库访问库),以下是实现动态更新的完整方案:
1. 定义样例类与表映射
首先是你的Person样例类,以及对应的Slick表映射:
case class Person(id: Long, firstName: Option[String], age: Option[Int], email: Option[String], address: Option[String]) import slick.jdbc.H2Profile.api._ class Persons(tag: Tag) extends Table[Person](tag, "PERSONS") { def id = column[Long]("ID", O.PrimaryKey) def firstName = column[Option[String]]("FIRST_NAME") def age = column[Option[Int]]("AGE") def email = column[Option[String]]("EMAIL") def address = column[Option[String]]("ADDRESS") override def * = (id, firstName, age, email, address) <> (Person.tupled, Person.unapply) } val persons = TableQuery[Persons]
2. 动态构建更新方法
核心逻辑是筛选出传入对象中所有非None的字段,仅将这些字段加入更新语句:
def updatePerson(person: Person): DBIO[Int] = { // 收集需更新的列与对应值,过滤掉None项 val updatePairs = Seq( person.firstName.map(persons.map(_.firstName) -> _), person.age.map(persons.map(_.age) -> _), person.email.map(persons.map(_.email) -> _), person.address.map(persons.map(_.address) -> _) ).flatten if (updatePairs.isEmpty) { // 无字段需更新,直接返回0行更新结果 DBIO.successful(0) } else { // 动态生成更新语句,仅包含非空字段 val updateQuery = persons .filter(_.id === person.id) .map(_ => updatePairs.map(_._1)) .update(updatePairs.map(_._2)) updateQuery } }
3. 使用示例
对于你提供的person1对象,调用方法后只会更新address字段:
val person1 = Person(1, None, None, None, Some("33, xyz st")) // 执行更新(需提前配置数据库连接) val db = Database.forConfig("your-db-config") try { val updatedRows = db.run(updatePerson(person1)).await println(s"成功更新 $updatedRows 行") } finally db.close()
其他ORM(以Quill为例)
如果使用Quill,核心思路一致,动态拼接更新表达式:
import io.getquill._ val ctx = new SqlMirrorContext(PostgresDialect, SnakeCase) import ctx._ def updatePersonQuill(person: Person): Unit = { val updateFields = List( person.firstName.map(f => _.firstName -> lift(f)), person.age.map(a => _.age -> lift(a)), person.email.map(e => _.email -> lift(e)), person.address.map(addr => _.address -> lift(addr)) ).flatten if (updateFields.nonEmpty) { val updateQuery = quote { query[Person] .filter(_.id == lift(person.id)) .update(updateFields: _*) } ctx.run(updateQuery) } }
核心逻辑总结
无论使用哪种数据库访问库,关键都是只将传入对象中Some类型的字段纳入更新范围,避免用None覆盖数据库中已存在的有效值,实现精准的条件更新。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

