anorm动态过滤器

时间:2012-11-22 16:17:08

标签: scala playframework playframework-2.0 anorm

我正在研究anorm文档(来自播放框架)并且不清楚它是否支持常见的查询用例:动态过滤器,即用户在10个字段的搜索表单中填写2或3个搜索条件

在这种情况下,如何在没有经典字符串操作的情况下动态构造查询?

3 个答案:

答案 0 :(得分:13)

是的,我认为Robin Green引用的问题包含答案。只需使用占位符(例如{criterion1})定义包含所有可能条件的查询,然后在查询上调用on()方法,传递SeqOption参数,如上所述接受的答案。


来自Anorm doc的修改示例,假设您有两个条件,但只希望您的查询过滤国家/地区代码而不是资本:

SQL(
"""
select * from Country c 
join CountryLanguage l on l.CountryCode = c.Code 
where ({countryCode} is null or c.code = {countryCode})
  and ({capital} is null or c.capital = {capital});
"""
).on("countryCode" -> Some("FRA"), "capital" -> None)

这应该可以解决问题。

答案 1 :(得分:3)

首先简短回答。假设您在数据库中有一个包含3列的表:nameemailpass。但是,从用户那里,您只有namepassword,而不是email。所以制作所有3的选项

val name:Option[String] = Some("alice")
val email:Option[String] = None
val pass:Option[String] = Some("password")

//For db insertion have this:

  DB.withConnection { implicit conn =>
  SQL("INSERT INTO USERS (name,email,pass) VALUES ({n},{e},{p})").on(
 'n -> name, 'e -> email,'p -> pass).executeInsert()
 }

执行上述操作时,emailNone,它会在您的数据库中插入null。因此,对于您的所有10列,您可以在上面的SQL语句中定义它们,并在Option中传递on()。如果它们中的任何一个是None,那么它将在数据库中将其作为null

如果架构中的列存在NOT NULL限制,则可能会出现问题。在这种情况下,您可以将getOrElse用于以下列:

DB.withConnection { implicit conn =>
  SQL("INSERT INTO USERS (name,email,pass) VALUES ({n},{e},{p})").on(
 'n -> name, 'e -> email.getOrElse("Default Email"),'p -> pass).executeInsert()

以下是关于Play如何将类型转换为数据库类型的理解列表。它可以在对象anorm.ToStatement中找到:

        case Some(bd: java.math.BigDecimal) => stmt.setBigDecimal(index, bd)
        case Some(o) => stmt.setObject(index, o)
        case None => stmt.setObject(index, null)
        case bd: java.math.BigDecimal => stmt.setBigDecimal(index, bd)
        case date: java.util.Date => stmt.setTimestamp(index, new java.sql.Timestamp(date.getTime()))
        case o => stmt.setObject(index, o)

上面你看,对于None,它将它视为空。


SELECT hmm的情况下,我不知道任何有助于此的anorm功能,但我想简单的String操作可能就足够了:

def getColumns(xs:List[Option[_]]):String = {
    val notNone = xs.collect{
       case Some(x) => x.toString
    }
    notNone.mkString(",")
}

然后SQL("SELECT %s from table".format(getColumns(List(nameColumn,emailColumn,passColumn)))

虽然这不是你想要的。 Anorm只是一个sql构建库。要做你想做的事,它还必须记住你的表模式(即至少列名......)。我认为没有做过那么多的事情

答案 2 :(得分:0)

Anorm似乎是谨慎操作的前提是您插入普通的旧SQL,没有任何功能,如类型安全或查询构建。它可能不是动态查询的正确工具。构造查询最终必须是字符串操作,因此我建议使用一个为您执行此操作的库。使用Anorm集成任何用于生成SQL语句的库应该很容易。

您可以动态构造查询,并使用类似jOOQ的库将该查询字符串传递给Anorm。作为奖励,您将获得许多数据库的支持。 jOOQ似乎很受欢迎,但可能还有许多其他库可供您使用。如果它不适合您的项目,请完全替换Anorm。