2012-12-28 69 views
27

我正在嘗試學習使用華而不實用來查詢MySQL。我有查詢的以下類型的工作,以得到一個訪問對象:斯卡拉華而不實的查詢列表中的位置

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

我想知道什麼是我可以改變上面的查詢得到一個列表[觀看]對於位置的集合。 ..something like:

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) 

這對Slick來說可能嗎?

+0

這不行嗎?應該管用。 –

+0

難道你不能堅持數值的元組嗎?這將確保您傳遞給查詢的參數數量是固定的。 –

回答

28

正如其他答案所示,這對靜態查詢很麻煩。靜態查詢界面要求您將綁定參數描述爲Product(Int, Int, String*) 不是有效的scala,並且使用(Int,Int,List[String])也需要一些kludges。此外,必須確保locationCodes.size始終等於(?, ?...)的數量,因此您在查詢中的內容很脆弱。

實際上,這並不是太大的問題,因爲您想要使用查詢monad,而這是使用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 

這是假設你有你的表建立這樣的:

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 _) 
} 

請注意,您可以隨時換您的查詢的方法。

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 
+0

這看起來很有希望。我到星期三才恢復工作,但我會盡量在這之前找點時間來測試一下,然後再報告。 – ShatyUT

+0

也可以使用s.th.像Parameters [List [Int]],然後用QueryTemplate「val byIdAndLocations」替換「def byIdAndLocations」? – longliveenduro

+0

你不能使用'val ids = List(1,2,3)| val結果:DBIO [Seq [T]] = query.filter(_。id inSet ID)'per http://stackoverflow.com/questions/17408444/is-it-possible-to-use-in-clause-in - 標準-SQL光滑#comment52439626_17422901? –

5

它不工作,因爲StaticQuery objectQ)預計隱式設置的參數在查詢字符串,使用query方法的類型參數,以創造一種二傳手對象(scala.slick.jdbc.SetParameter[T]類型)的。
SetParameter[T]的作用是將查詢參數設置爲類型爲T的值,其中所需類型取自query[...]類型參數。

從我看到有一個爲T = List[A]定義一個通用A沒有這樣的對象,這似乎是一個明智的選擇,因爲你不能真正寫入帶有參數的動態列表的SQL查詢的IN (?, ?, ?,...)條款


我沒有通過下面的代碼

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] 

範圍提供這樣一個隱含的價值與這個實驗,你應該能夠執行代碼

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) 

但你必須始終手動保證locationCodes大小相同的?數量在IN條款


最後,我認爲,一個更清潔的解決方法可以使用宏來創建,推廣序列類型。但我不確定這是否是框架的明智選擇,因爲上述問題與序列大小的動態性質有關。

3

您可以在第生成全自動這樣的:

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) 
    } 

而且使用隱式的setParameter爲pagoda_5b says

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] 
2

如果你有一個複雜的查詢和上面提到的理解不一個選項,您可以在Slick 3中執行下列操作。但是您需要確保自己驗證列表查詢參數中的數據以防止SQL注入:

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

變量引用前面的#禁用類型驗證,並允許您在不提供列表查詢參數的隱式轉換函數的情況下解決此問題。