【问题标题】:Compile error in filter with Slick mapped column type使用 Slick 映射列类型的过滤器编译错误
【发布时间】:2016-05-24 07:44:07
【问题描述】:

我在使用 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))
}

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

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

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    我不确定发生这种情况的确切原因。我认为这与在范围内进行模棱两可的隐式转换有关(到 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)
    }
    

    【讨论】:

    • 非常感谢您的意见!我不太了解inSet=== 的签名中发生的魔力,但我猜def inSet[R](seq: Traversable[B1])(implicit om: o#to[Boolean, R])Traversable 的协方差可能是它在没有a 的情况下工作的原因之一类型注释。我想知道是否可以修改 def === [P2, R](e: Rep[P2])(implicit om: o#arg[B1, P2]#to[Boolean, R]) 以使 === 的行为更直观。
    【解决方案2】:

    这是 Scala 问题,而不是 Slick 问题。不建议从对象扩展案例类。您的示例代码未显示如何使用案例类的 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]
    

    【讨论】:

    • 嗯,我从来没有听说过案例类不应该实现特征;恰恰相反,这是常见的做法,如OptionList 的实现等流行示例所示。此外,您提到的 override 关键字在我们正在讨论的代码中是完全可选的。最后但并非最不重要的一点是,我所指的枚举与您的一样是 ADT(由github.com/lloydmeta/enumeratum#slick-integration 增强)。至于回退到 Java 枚举:我已经有一个解决方法,在这种情况下我更喜欢它。
    • Mattias 注意到我的示例代码中的覆盖值。无论如何,你以某种方式解决了这个问题,所以你应该明天发布答案并标记它,或者删除问题
    • 你所指的对象是它正上方的trait的伴生对象。这个特征是我扩展的......
    • 至于override:这应该没什么区别,但我只是检查了一下绝对确定!因为我还不知道我做错了什么或者这是 Slick 中的一个错误,所以这个问题没有得到回答,我也不会删除它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-15
    相关资源
    最近更新 更多