2015-10-22 75 views
1

我的功能實現與使用光滑3.1.0需要創建表,如下圖所示:如何在函數中包含靈活的API implicits?

def ensureTables(db: backend.DatabaseDef, ts: Seq[TableQuery[_]]) { 
    val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf) 
    val ns = Set() ++ ts0.map(t => t.name.name) 

    for { 
     t <- ts 
    } Await.result(db.run(t.schema.create), Duration.Inf) 
    } 

這還沒有結束,因爲編譯錯誤(我想添加篩選表達)。錯誤在第七行:value schema is not a member of slick.driver.SQLiteDriver.api.TableQuery[_$1]。這是因爲在SQLiteDriver.API(在這種情況下爲tableQueryToTableQueryExtensionMethods)中定義的隱式函數未包含在內。

如何正確包含這些隱式函數?

回答

2

當我想讓我的DB代碼可插拔在光滑的不同的驅動程序我通常配置文件類型parametrise我的函數(或性狀/班),並提供配置文件作爲參數;在你的情況下,函數會是這個樣子:

def ensureTables[P <: JdbcProfile](profile: P)(db: profile.api.Database, ts: Seq[TableQuery[_]]) { 
    import profile.api._ 
    ... 
} 

如果功能是在聚集數據庫相關的功能性狀或類可以提供在類級別和進口存在的輪廓。

順便說一句,請注意,您阻止兩個線程,並可能導致死鎖每次使用Await;請使用未來的組合器(如flatMap)來編寫異步代碼。

+0

嗨Aldo,我試過這種解決方案,但它沒有奏效。然而,評論似乎不適合描述我所看到的內容,所以我在下面的答案中寫下了詳細信息。 – user2595776

+0

嗨阿爾多,經過一番調查後我終於解決了這個問題。我仍然會寫詳細信息,但您的解決方案是正確的。 – user2595776

1

TL;博士

注:這不是一個新的答案,只闡述由阿爾Stracquadanio提供了答案。它被寫爲答案,以便更友好地顯示更多細節。

起初,我嘗試以下的版本,這是簡單地將艾度的提示結果:

def ensureTables[P <: JdbcProfile] 
       (profile: P) 
       (db: profile.api.Database, ts: Seq[TableQuery[_]]) { 
    import profile.api._ 
    val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf) 
    val ns = Set() ++ ts0.map(t => t.name.name) 
    for (t <- ts) Await.result(db.run(t.schema.create), Duration.Inf) 
} 

錯誤仍然存​​在,作爲ts類型是錯誤的:由tableQueryToTableQueryExtensionMethods需要的類型Query[T, U, Seq] with TableQuery[T],而不是TableQuery[_],所以沒有暗示符合上述定義。

ensureTables正確的版本應該被實現爲這樣:

def ensureTables[P <: RelationalProfile, T <: RelationalProfile#Table[_], C[_]] 
       (profile: P) 
       (db: profile.api.Database, 
       ts: Seq[Query[T, _, C] with TableQuery[T]]) { 
    import profile.api._ 
    val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf) 
    val ns = Set() ++ ts0.map(t => t.name.name) 
    for (t <- ts) Await.result(db.run(t.schema.create), Duration.Inf) 
} 

這個功能本身編譯。然而,當我試圖把幾個TableQuery值加在一起並使用它,我有兩個新的錯誤:

ensureTables(profile)(db, Seq(circles, rectangles)) 

導致

[error] SlickProg.scala:40: no type parameters for method ensureTables: (db: slick.driver.SQLiteDriver.profile.api.Database, ts: Seq[slick.driver.SQLiteDriver.api.Query[T, _, C] with slick.driver.SQLiteDriver.api.TableQuery[T]])Unit exist so that it can be applied to arguments (slick.driver.SQLiteDriver.backend.DatabaseDef, Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]]) 
[error] --- because --- 
[error] argument expression's type is not compatible with formal parameter type; 
[error] found : Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]] 
[error] required: Seq[slick.driver.SQLiteDriver.api.Query[?T, _, ?C] with slick.driver.SQLiteDriver.api.TableQuery[?T]] 
[error]  (which expands to) Seq[slick.lifted.Query[?T, _, ?C] with slick.lifted.TableQuery[?T]] 
[error]  ensureTables(profile)(db, Seq(circles, rectangles)) 
[error]    ^
[error] SlickProg.scala:40: type mismatch; 
[error] found : Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]] 
[error] required: Seq[slick.driver.SQLiteDriver.api.Query[T, _, C] with slick.driver.SQLiteDriver.api.TableQuery[T]] 
[error]  (which expands to) Seq[slick.lifted.Query[T, _, C] with slick.lifted.TableQuery[T]] 
[error]  ensureTables(profile)(db, Seq(circles, rectangles)) 
[error]        ^
[error] two errors found 

這是由於將不同類型的值到一個單一的序列導致出乎意料的鍵入順序。編譯器計算序列元素的通用類型(_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable])。

我結束了下面的實現,以表從ensureTable功能外遍歷:

def ignore[T](x: T): Unit =() 

def valueOf[T](f: Future[T]): T = Await.result(f, Duration.Inf) 

def ensureTable[P <: RelationalProfile, T <: RelationalProfile#Table[_], C[_]] 
       (p: P) 
       (db: p.api.Database, ns: Set[String], 
       t: Query[T, _, C] with TableQuery[T]) { 
    import p.api._ 
    val n = t.shaped.value.tableName 
    if (!ns.contains(n)) 
    ignore(valueOf(db.run(t.schema.create))) 
} 

def tablesOf[P <: RelationalProfile](p: P)(db: p.api.Database): Seq[MTable] = 
    valueOf(db.run(MTable.getTables)) 

val names = Set() ++ tablesOf(profile)(db).map(_.name.name) 
for (t <- Seq(circles, rectangles)) ensureTable(profile)(db, names, t) 

謝謝阿爾Stracquadanio。

相關問題