2016-05-23 42 views
1

我無法使用slick-3.1.1過濾定製類型。下面,自包含的例子,說明我的問題:如果我在我的定義,並在MappedColumnType使用SomeType,而不是SomeBaseType在使用Slick映射列類型的過濾器中編譯錯誤

object IllustrateSlickQuestion { 
    val sqlDriver = slick.driver.PostgresDriver 
    import sqlDriver.api._ 

    trait SomeBaseType { 
    def value: Int 
    } 

    object SomeBaseType { 
    def apply(value: Int): SomeBaseType = SomeType(value) 
    } 

    case class SomeType(value: Int) extends SomeBaseType 

    implicit val someBaseTypeMappedColumnType = MappedColumnType.base[SomeBaseType, Int](_.value, SomeBaseType.apply) 

    class SomeTable(tag: Tag) extends Table[(SomeBaseType, Option[SomeBaseType])](tag, "my_table") { 
    def someColumn = column[SomeBaseType]("some_column") 
    def someNullableColumn = column[Option[SomeBaseType]]("some_nullable_column") 
    def * = (someColumn, someNullableColumn) 
    } 

    val someTable = TableQuery[SomeTable] 

    // These selects work: 
    val compilingSelect1 = someTable.filter(_.someColumn inSet Set(SomeType(42))) 
    val compilingSelect2 = someTable.filter(_.someNullableColumn inSet Set(SomeType(42))) 

    // Does not compile: 
    // [error] type mismatch; 
    // [error] found : IllustrateSlickQuestion.SomeType 
    // [error] required: slick.lifted.Rep[?] 
    // [error] val brokenSelect1 = someTable.filter(_.someColumn === SomeType(42)) 
    val brokenSelect1 = someTable.filter(_.someColumn === SomeType(42)) 

    // Does not compile either: 
    // [error] see above 
    val brokenSelect2 = someTable.filter(_.someNullableColumn === SomeType(42)) 
} 

這個問題消失。然而,這不是我真正關心的代碼中的一個選項,因爲SomeBaseType代表枚舉。因此我堅持使用inSet而不是===作爲解決方法。

我做錯了什麼,或者這是Slick中的錯誤?

回答

0

這是一個Scala問題,而不是一個問題。不推薦從一個對象擴展一個案例類。您的示例代碼不顯示如何使用案例類的value屬性。你的意思是覆蓋基類value屬性嗎?如果是這樣,那麼你需要寫:

case class SomeType(override val value: Int) extends SomeBaseType 

但是,你會遇到問題。您可能會發現一個ADT最好使用Enumerator

sealed trait MyEnum 
trait EnumValue1 extends MyEnum 
trait EnumValue2 extends MyEnum 
trait EnumValue3 extends MyEnum 

那麼你也許可以寫出像這樣(未測試):

case class SomeType(myEnum: MyEnum) extends AnyVal with MappedTo[Int] 

我的選擇是使用Java枚舉:

public enum MyEnum { 
    EnumValue1 , EnumValue2, EnumValue3 
} 

然後寫:

case class SomeType(myEnum: MyEnum) extends AnyVal with MappedTo[Int] 
+0

嗯,我從來沒有聽說過,案例類不應該實現特質;恰恰相反,這是常見的做法,像'Option'這樣的流行示例或List的實現顯示。另外,您提到的'override'關鍵字在我們正在討論的代碼中完全是可選的。最後但並非最不重要的一點,我所指的枚舉就像您的枚舉(通過https://github.com/lloydmeta/enumeratum#slick-integration增強)。至於回到Java枚舉:我已經有了一個解決方法,我寧願在這種情況下。 –

+0

Mattias注意到我的示例代碼中的重寫val。無論如何,你以某種方式解決了這個問題,所以你應該發佈答案並在明天標記它,或者刪除問題 –

+0

你指的對象是直接位於它上面的特徵的伴隨對象。這個特點是我擴展.... –

2

我不確定發生這種情況的確切原因。我認爲它與範圍中的含糊不清的隱式轉換有關(包括Rep [SomeBaseType]和Rep [Option [SomeBaseType]])。所以編譯器不知道選擇哪個(因此也不選擇)。但我可能是錯的。我有你的一些解決方法:

// Adding a type annotation to the filter: 
val fixedSelect1 = someTable.filter(_.someColumn === (SomeType(42):SomeBaseType)) 

// Using a helper method: 
def query(someType: Rep[SomeBaseType]) = 
    someTable.filter(_.someNullableColumn === someType) 

query(SomeType(42)) 

// With compiled queries 
val query = Compiled { (someType: Rep[SomeBaseType]) => 
    someTable.filter(_.someNullableColumn === someType) 
} 
+0

非常感謝您的意見!我並不十分理解'inSet'和'==='簽名的魔力,但我猜'set in [R]中的Traversable的協方差(seq:Traversable [B1] )(隱含的om:o#to [Boolean,R])'可能是它在沒有類型註釋的情況下工作的原因之一。我想知道是否可以修改'def === [P2,R](e:Rep [P2])(隱含的om:o#arg [B1,P2] #to [Boolean,R])' ==='表現得更直觀。 –