Динамические параметры SQL с Anorm и Scala Play Framework
Можно ли динамически создать список для метода anorm "on"?
У меня есть форма с дополнительными вводами, и в настоящее время я проверяю каждую опцию и создаю список с определенными параметрами и пытаюсь передать это до анома. В настоящее время я получаю эту ошибку компиляции
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
Важно то, что вам нужно создавать значения типа 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: _*
)
Ответ 2
Таким образом, я в конечном итоге просто звонил несколько раз.
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 *)
Ответ 3
Вы можете посмотреть, что многозначный параметр следующий Anorm (следующий Play 2.3/master).