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
相关产品推荐
相关产品推荐

