You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala Slick项目中实现关联表动态多条件过滤的方法问询

我来帮你解决这个Slick的过滤逻辑问题,核心是要实现单个Params内部参数用AND关联、多个Params之间用OR关联的组合逻辑,下面一步步拆解实现:

解决方案:Slick多条件OR+内部AND过滤实现

1. 先修正表定义的小问题

你的UserDevicesTable字段命名有歧义(把device_name映射成了name,容易和User表的name混淆),同时表类的继承也需要补全,先修正这部分:

final class UserTable(tag: Tag) extends Table[UserRow](tag, "user") {
  def id = column[UUID]("id")
  def name = column[String]("name")
  def surname = column[String]("surname")
  def * = (id, name, surname).mapTo[UserRow]
}

final class UserDevicesTable(tag: Tag) extends Table[UserDevices](tag, "user_devices") {
  def id = column[UUID]("id")
  def userId = column[UUID]("user_id")
  def deviceName = column[Option[String]]("device_name") // 修正字段名,避免歧义
  def deviceModel = column[Option[String]]("device_model") // 修正字段名
  def * = (id, userId, deviceName, deviceModel).mapTo[UserDevices]
}

2. 核心过滤逻辑实现

要实现目标逻辑,我们需要把每个Params转换成对应的AND条件,再把所有条件用OR串联起来。修改你的filter方法如下:

def filter(filterBy: FilterBy): Future[Seq[UserRow]] = {
  // 初始化表查询对象(假设你已经完成DB连接等基础配置)
  val userTable = TableQuery[UserTable]
  val userDevicesTable = TableQuery[UserDevicesTable]

  // 把Params列表转换为Slick可识别的过滤条件
  val filterCondition = filterBy.params.map { paramsList =>
    // 遍历每个Params,生成单条AND条件
    val singleParamConditions = paramsList.map { param =>
      // 收集非空的过滤参数,生成对应条件
      val nameCondition = param.deviceName.map(name => userDevicesTable.deviceName === name)
      val modelCondition = param.deviceModel.map(model => userDevicesTable.deviceModel === model)
      
      // 将非空条件用AND连接;如果两个参数都为空,则生成永真条件(可根据业务调整为抛出错误)
      List(nameCondition, modelCondition).flatten.reduceOption(_ && _).getOrElse(LiteralColumn(true))
    }
    
    // 将所有单条条件用OR连接;如果参数列表为空,则生成永真条件
    singleParamConditions.reduceOption(_ || _).getOrElse(LiteralColumn(true))
  }

  val query = userTable
    .join(userDevicesTable) // 你的目标SQL是内连接,而非左连接,所以用join
    .on(_.id === _.userId)
    .filterOpt(filterCondition) { case ((_, _), condition) => condition }
    .map(_._1)
    .distinct // 避免同一用户因多个符合条件的设备被重复返回
    .result

  db.run(query)
}

3. 关键逻辑说明

  • 单个Params的AND逻辑:对每个Params,只处理非None的参数,用reduceOption(_ && _)把参数条件串联成AND关系;如果参数全为空,返回永真条件(业务上可改为忽略该参数或抛出异常)。
  • Params列表的OR逻辑:把所有单个Params的AND条件用reduceOption(_ || _)串联,实现多条件OR关联。
  • 内连接与去重:使用join匹配你的目标SQL逻辑,同时用distinct避免同一用户因多个符合条件的设备被重复查询出来。

4. 测试示例

当你传入如下参数时:

val targetFilter = FilterBy(Some(List(
  Params(Some("Samsung"), Some("A20")),
  Params(Some("Xiaomi"), None)
)))

生成的SQL会完全匹配你给出的目标查询:

SELECT DISTINCT u.* FROM "user" u 
JOIN user_devices ON u.id = user_devices.user_id 
WHERE (device_name = 'Samsung' AND device_model = 'A20') OR device_name = 'Xiaomi'

内容的提问来源于stack exchange,提问作者Slavik Muz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:07:50