voladores pequeños patas para nombres niños muy lista insectos fotos comunes cientificos casa campo antenas scala typesafe-stack slick

scala - pequeños - nombres de insectos comunes y cientificos



Scala consulta pulida donde en lista (4)

Como lo sugiere la otra respuesta, esto es complicado de hacer con las consultas estáticas. La interfaz de consulta estática requiere que describas los parámetros de enlace como un Product . (Int, Int, String*) no es válido scala, y el uso de (Int,Int,List[String]) necesita algunos kludges. Además, tener que asegurarse de que locationCodes.size sea ​​siempre igual al número de (?, ?...) que tiene en su consulta es frágil.

En la práctica, esto no es un problema demasiado grande porque desea utilizar la mónada de consulta en su lugar, que es la forma segura y recomendada de usar Slick.

val visitorId: Int = // whatever val locationCodes = List("loc1","loc2","loc3"...) // your query, with bind params. val q = for { v <- Visits if v.visitor is visitorId.bind if v.location_code inSetBind locationCodes } yield v // have a look at the generated query. println(q.selectStatement) // run the query q.list

Esto es asumiendo que tienes tus tablas configuradas de esta manera:

case class Visitor(visitor: Int, ... location_code: String) object Visitors extends Table[Visitor]("visitor") { def visitor = column[Int]("visitor") def location_code = column[String]("location_code") // .. etc def * = visitor ~ .. ~ location_code <> (Visitor, Visitor.unapply _) }

Tenga en cuenta que siempre puede ajustar su consulta en un método.

def byIdAndLocations(visitorId: Int, locationCodes: List[String]) = for { v <- Visits if v.visitor is visitorId.bind if v.location_code inSetBind locationCodes } yield v } byIdAndLocations(visitorId, List("loc1", "loc2", ..)) list

Estoy intentando aprender a usar Slick para consultar MySQL. Tengo el siguiente tipo de consulta trabajando para obtener un solo objeto Visit:

Q.query[(Int,Int), Visit](""" select * from visit where vistor = ? and location_code = ? """).firstOption(visitorId,locationCode)

Lo que me gustaría saber es cómo puedo cambiar lo anterior para consultar y obtener una [Visita] de una colección de ubicaciones ... algo como esto:

val locationCodes = List("loc1","loc2","loc3"...) Q.query[(Int,Int,List[String]), Visit](""" select * from visit where vistor = ? and location_code in (?,?,?...) """).list(visitorId,locationCodes)

¿Es esto posible con Slick?


No funciona porque el StaticQuery object ( Q ) espera establecer implícitamente los parámetros en la cadena de consulta, usando los parámetros de tipo del método de query para crear una especie de objeto de establecimiento (de tipo scala.slick.jdbc.SetParameter[T] ).
La función de SetParameter[T] es establecer un parámetro de consulta en un valor de tipo T , donde los tipos requeridos se toman de los parámetros de tipo de consulta.

Por lo que veo, no hay tal objeto definido para T = List[A] para una A genérica, y parece una opción sensata, ya que no se puede escribir una consulta de SQL con una lista dinámica de parámetros para el IN (?, ?, ?,...) cláusula

Hice un experimento proporcionando un valor implícito a través del siguiente código

import scala.slick.jdbc.{SetParameter, StaticQuery => Q} def seqParam[A](implicit pconv: SetParameter[A]): SetParameter[Seq[A]] = SetParameter { case (seq, pp) => for (a <- seq) { pconv.apply(a, pp) } } implicit val listSP: SetParameter[List[String]] = seqParam[String]

Con esto en alcance, deberías poder ejecutar tu código

val locationCodes = List("loc1","loc2","loc3"...) Q.query[(Int,Int,List[String]), Visit](""" select * from visit where vistor = ? and location_code in (?,?,?...) """).list(visitorId,locationCodes)

¿Pero siempre debe garantizar manualmente que el tamaño de locationCodes códigos de locationCodes sea ​​el mismo que el número de ? en su cláusula IN

Al final, creo que se podría crear una solución más limpia utilizando macros, para generalizar en el tipo de secuencia. Pero no estoy seguro de que sea una elección acertada para el marco, dados los problemas mencionados anteriormente con la naturaleza dinámica del tamaño de la secuencia.


Puedes generar en cláusula automáticamente de esta manera:

def find(id: List[Long])(implicit options: QueryOptions) = { val in = ("?," * id.size).dropRight(1) Q.query[List[Long], FullCard](s""" select o.id, o.name from organization o where o.id in ($in) limit ? offset ? """).list(id ::: options.limits) }

Y use SetParameter implícito como dice pagoda_5b

def seqParam[A](implicit pconv: SetParameter[A]): SetParameter[Seq[A]] = SetParameter { case (seq, pp) => for (a <- seq) { pconv.apply(a, pp) } } implicit def setLongList = seqParam[Long]


Si tiene una consulta compleja y para la comprensión mencionada anteriormente no es una opción, puede hacer algo como lo siguiente en Slick 3. Pero debe asegurarse de validar los datos en su parámetro de consulta de lista para evitar la inyección de SQL:

val locationCodes = "''" + List("loc1","loc2","loc3").mkString("'',''") + "''" sql""" select * from visit where visitor = $visitor and location_code in (#$locationCodes) """

El # en frente de la referencia de variable desactiva la validación de tipo y le permite resolver esto sin proporcionar una función para la conversión implícita del parámetro de consulta de lista.