Anorm 和 Scala Play 框架中的动态 SQL 参数

15

如何在anorm的“on”方法中动态创建列表?

我有一个带有可选输入的表单,目前我检查每个选项并创建一个定义了选项的列表,并尝试将其传递给anorm。目前我遇到了编译错误。

type mismatch; found : List[java.io.Serializable] required: (Any, anorm.ParameterValue[_])
我不确定该如何创建这个列表。 当前代码:

val onList = List(
        'school_id = input.school,
        if(input.rooms isDefined)       ('rooms -> input.rooms) else "None" ,
        if(input.bathrooms isDefined)   ('bathrooms -> input.bathrooms) else "None" ,
        if(input.houseType isDefined)   ('houseType -> input.houseType) else "None" ,
        if(input.priceLow isDefined)    ('priceLow -> input.priceLow) else "None" ,
        if(input.priceHigh isDefined)   ('priceHigh -> input.priceHigh) else "None" ,
        if(input.utilities isDefined)   ('utilities -> input.utilities) else "None" 
).filter(_!="None")
SQL("SELECT * FROM Houses WHERE " + whereString).on(onList).as(sqlToHouse *)

最初我尝试做这件事是因为我认为它会和...一样,但现在我发现并非如此。

.on('rooms -> input.rooms, 'bathroom -> input.bathrooms... etc)

编辑:

代码现在为:

val onList = Seq(
        ('school_id -> input.school),
        if(input.rooms isDefined)       ('rooms -> input.rooms.get)         else None ,
        if(input.bathrooms isDefined)   ('bathrooms -> input.bathrooms.get) else None ,
        if(input.houseType isDefined)   ('houseType -> input.houseType.get) else None ,
        if(input.priceLow isDefined)    ('priceLow -> input.priceLow.get)   else None ,
        if(input.priceHigh isDefined)   ('priceHigh -> input.priceHigh.get) else None ,
        if(input.utilities isDefined)   ('utilities -> input.utilities.get) else None 
).filter(_!=None).asInstanceOf[Seq[(Any,anorm.ParameterValue[_])]]

使用SQL命令:

SQL("SELECT * FROM Houses WHERE " + whereString).on(onList:_*).as(sqlToHouse *)

现在出现了异常

[ClassCastException: java.lang.Integer cannot be cast to anorm.ParameterValue]

1
这个应该怎么工作?whereString看起来像什么? - Robin Green
3个回答

12

重要的是你必须创建类型为ParameterValue的值。通常使用toParameterValue()函数来完成此操作。

一种方法是创建一个选项序列,然后将其展平:

val onList = Seq(
  Some('school_id -> input.school),
  input.rooms.map('rooms -> _),
  input.bathrooms.map('bathrooms -> _)
).flatten

这个序列可以映射到正确的值:

SQL(
  "SELECT * FROM Houses WHERE " + whereString
).on(
  onList.map(v => v._1 -> toParameterValue(v._2)): _*
)
这可以简化为以下内容:

val onList = Seq(
  Some('school_id -> input.school),
  input.rooms.map('rooms -> _),
  input.bathrooms.map('bathrooms -> _)
).flatMap(_.map(v => v._1 -> toParameterValue(v._2)))

SQL(
  "SELECT * FROM Houses WHERE " + whereString
).on(
  onList: _*
)

或许最简单的解决方案是这样的:


val onList = Seq(
  Some('school_id -> toParameterValue(input.school)),
  input.rooms.map('rooms -> toParameterValue(_)),
  input.bathrooms.map('bathrooms -> toParameterValue(_))
).flatten

SQL(
  "SELECT * FROM Houses WHERE " + whereString
).on(
  onList: _*
)

太棒了!我不知道 toParameterValue 函数。谢谢。 - damian

1

您可以查看多值参数是下一个Anorm(即将推出的Play 2.3 / master)中的内容。


1
所以最终我只是多次调用了它。
var query = SQL("SELECT * FROM Houses WHERE " + whereString).on('school_id -> input.school)
if(input.rooms isDefined)       query= query.on('rooms -> input.rooms.get)
if(input.bathrooms isDefined)   query= query.on('bathrooms -> input.bathrooms.get)
if(input.houseType isDefined)   query= query.on('houseType -> input.houseType.get)
if(input.priceLow isDefined)    query= query.on('priceLow -> input.priceLow.get)
if(input.priceHigh isDefined)   query= query.on('priceHigh -> input.priceHigh.get)
if(input.utilities isDefined)   query= query.on('utilities -> input.utilities.get)
query.as(sqlToHouse *)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接