【问题标题】:How to add multiple or filter conditions based on incoming parameters using exposed?如何使用暴露的基于传入参数添加多个或过滤条件?
【发布时间】:2019-01-25 08:26:11
【问题描述】:

我必须使用参数值将or 条件添加到查询中。

示例:select * from users where email = "abc@xyz.com" or phone="1234123412";

用户可以发送两个字段或只发送一个。我想在每个字段的循环中执行此操作,并将它们中的每一个添加到or where 条件中。

val query = Users.selectAll()
**var predicates = Op.build { Users.id inList listOf<Int>()}**
for((k, v) in params) {
    val value = URLDecoder.decode(v.first(), "UTF-8")
    predicates = when(k) {
        "email" -> predicates.or(Users.email eq value)
        "phone" -> predicates.or(Users.phone eq value)
    }
}
query.andWhere { predicates }

上面的 DSL 产生下面的 SQL。

SELECT * from users where (((false = true) OR (users.email = "abc@xyz.com")) OR (users.phone = "1234567890"))

看到false = true了吗?那是因为,要使用.or 方法,我必须使用条件进行初始化。下面给出的 sn-p 是添加用于初始化谓词的不必要的代码行。

var predicates = Op.build { Users.id inList listOf<Int>()}

什么是初始化它的正确方法,以便我可以无缝地将多个orand 谓词添加到查询中?

【问题讨论】:

  • AFAIK 几乎所有最终创建 SQL 的框架/库都使用这种子句。从 DSL 的角度来看,它们只是更好。如果存在 0 或 1 个条件,它们会删除对 orand 的特殊处理。 SQL 引擎将简单地忽略它们,因此没有真正的缺点。只需查看由 hibernate 生成的查询。它们充满了1=01=1 之类的东西。因此,您可能无法轻松删除它们。

标签: kotlin kotlin-exposed


【解决方案1】:

首先,我建议您优化您的代码,例如:

    val params = mapOf<String, List<String>>()
    val emails = params.filterKeys { it == "email" }.map { URLDecoder.decode(it.value.first(), "UTF-8") }
    val phones = params.filterKeys { it == "phone" }.map { URLDecoder.decode(it.value.first(), "UTF-8") }

    if (emails.isEmpty() && phones.isEmpty()) {
        error("No suitable params were provided")
    } else {
        Users.select {
            Users.email inList emails or (Users.phone inList phones)
        }
    }

UPD:orWhere 函数从 0.16.1 版本开始在 Exposed 中可用。

如果您想使用模式匹配 (when),请按照 andWhere 的工作方式定义您的本地 orWhere 函数:

fun Query.orWhere(andPart: SqlExpressionBuilder.() -> Op<Boolean>) = adjustWhere {
    val expr = Op.build { andPart() }
    if(this == null) expr
    else this or expr
}

并像这样使用它:

val query = Users.selectAll()
for((k, v) in params) {
    val value = URLDecoder.decode(v.first(), "UTF-8")
    predicates = when(k) {
        "email" -> query.orWhere { Users.email eq value }
        "phone" -> query.orWhere{ Users.phone eq value }
    }
}

【讨论】:

    【解决方案2】:

    一个技巧是将predicates初始化为null并在Op&lt;Boolean&gt;?上定义自己的orand

    // not sure x's type is correct here, the wiki doesn't give exact signatures
    // may also need @JvmName to allow overloading
    fun Op<Boolean>?.or(x: Op<Boolean>) = if (this != null) this.or(x) else x
    
    ...
    var predicates: Op<Boolean>? = null
    ...
    predicates = when(k) {
        "email" -> predicates.or(Users.email eq value)
        "phone" -> predicates.or(Users.phone eq value)
    }
    

    是否值得复杂化,我怀疑:正如 Giacomo 的评论所提到的,数据库肯定会优化你原来的 false = true

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-30
      • 1970-01-01
      • 2022-07-21
      • 2021-12-14
      • 1970-01-01
      • 2017-09-06
      • 2021-07-15
      • 1970-01-01
      相关资源
      最近更新 更多