使用Slick映射列类型在过滤器中编译错误

时间:2016-05-23 11:27:23

标签: scala slick

我无法使用slick-3.1.1过滤自定义类型。以下自包含示例说明了我的问题:

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

如果我在定义和SomeType中使用SomeBaseType代替MappedColumnType,则此问题就会消失。然而,这不是我真正关心的代码中的一个选项,因为SomeBaseType表示枚举。因此,我坚持使用inSet代替===作为解决方法。

我做错了什么,或者这是Slick中的错误?

2 个答案:

答案 0 :(得分:3)

我不确定发生这种情况的确切原因。我认为这与范围内的模糊隐式转换(包括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)
}

答案 1 :(得分:0)

这是一个Scala问题,而不是Slick问题。不建议从对象扩展案例类。您的示例代码未显示如何使用案例类的Exp : let var '=' Exp in Exp { Let $2 $4 $6 } | Exp1 { Exp1 $1 } Exp1 : Exp1 '+' Term { Plus $1 $3 } | Exp1 '-' Term { Minus $1 $3 } | Term { Term $1 } Term : Term '*' Factor { Times $1 $3 } | Term '/' Factor { Div $1 $3 } | Factor { Factor $1 } Factor : int { Int $1 } | var { Var $1 } | '(' Exp ')' { Brack $2 } 属性。您是否要覆盖基类value属性?如果是这样,那么你需要写:

value

但是,您会遇到问题。您可能会发现ADT优于使用case class SomeType(override val value: Int) extends SomeBaseType

Enumerator

然后你可能会写这样的东西(未经测试):

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

我的偏好是使用Java枚举:

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

然后写:

public enum MyEnum {
    EnumValue1 , EnumValue2, EnumValue3
}