【问题标题】:Filtering when using custom column type in Slick在 Slick 中使用自定义列类型时进行过滤
【发布时间】:2015-08-09 14:50:44
【问题描述】:

在使用自定义列类型时,我在 Slick 2.1.0 中查询/过滤时遇到了一些困难。 我的问题的简化版本:

import scala.slick.driver.MySQLDriver.simple._

sealed class Status(val intValue: Int)
case object Active extends Status(1)
case object Disabled extends Status(2)
case object Deleted extends Status(3)

case class TableMapping(id: Long, status: Status)

class MyTableDefinition(tag: Tag) extends Table[TableMapping](tag, "sometable") {
  implicit val statusColumnType = MappedColumnType.base[Status, Int](statusToInt, intToStatus)

  def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
  def status = column[Status]("STATUS", O.NotNull, O.Default(Active))
  def * = (id, status) <> (TableMapping.tupled, TableMapping.unapply)

  private def statusToInt(s: Status): Int = s.intValue
  private def intToStatus(i: Int): Status = i match {
    case 1 => Active
    case 2 => Disabled
    case _ => Deleted
  }
}

class MyTableDao {
    val Items = TableQuery[MyTableDefinition]
    def byId(id: Long)(implicit session: Session): Option[TableMapping] = {
      Items.filter(_.status =!= Deleted).firstOption
    }
}

我得到一个编译错误:

Items.filter(_.status =!= Deleted).firstOption

错误状态:

value =!= is not a member of scala.slick.lifted.Column[Status]
[error] def byId(id: Long)(implicit session: Session): Option[TableMapping] =
  Items.filter(_.status =!= Deleted).firstOption

对我做错了什么有任何想法吗?也许我不知道有更好的方法来做到这一点?

【问题讨论】:

    标签: scala slick slick-2.0


    【解决方案1】:

    问题是 Scala 编译器会寻找 Deleted.type 的隐式转换,而不是 Status

    由于Deleted 被声明为object,它不是一个类,它的实际类是Deleted.type,所以你只需要帮助编译器理解它实际上是一个Status。如何?你可以试试

    class MyTableDao {
    val Items = TableQuery[MyTableDefinition]
    
    def byId(id: Long)(implicit session: Session): Option[TableMapping] =
        Items.filter(_.status =!= Deleted.asInstanceOf[Status]).firstOption
    }
    

    这样就可以了。

    如果它确实有效,请告诉我,我面临着类似的问题,我能够摆脱它。

    【讨论】:

    • 在 Slick 3 中仍然相关。谢谢!
    • 你不应该在 DAO 上这样做。这是昂贵的。使用类型注释参考:groups.google.com/d/msg/scalaquery/prrMbK0jcR8/GjZ9i3aKEgAJ
    • 谢谢梅西和里斯!这两个技巧都奏效了,但与 Rhys 的一样。
    • 实现这项工作的唯一方法是在与表相同的类中创建包含过滤逻辑的存储库方法吗?我宁愿不这样做,但我还没有弄清楚如何将隐式密封特征列映射器从表类中取出并返回到想要进行过滤的业务逻辑。
    【解决方案2】:

    您的自定义类型映射器需要在 DAO 的范围内;我会做类似的事情:

    trait MyTypeMapper {
      protected implicit val statusColumnType = 
        MappedColumnType.base[Status, Int](_.intValue, intToStatus)
    
      private def intToStatus(i: Int): Status = i match {
        case 1 => Active
        case 2 => Disabled
        case _ => Deleted
      }
    }
    

    然后将 trait 混合到你的表映射器和 dao 中:

    class MyTableDefinition(tag: Tag) 
      extends Table[TableMapping](tag, "sometable")
      with MyTypeMapper {...}
    
    class MyTableDao extends MyTypeMapper{...}
    

    【讨论】:

    • 我刚试过这种方法。它解决了我最初的编译错误。但是,我现在收到以下错误: [error] found : Deleted.type [error] required: scala.slick.lifted.Column[?] [error] Items.filter(_.status =!= Deleted).firstOption Any想法?
    • 我为此创建了一个小型测试应用程序:link。如果你编译它,你会在使用这种方法时看到两个错误。
    • .filter(_.status =!= Deleted.bind)
    • 嗯,没有骰子:值绑定不是对象 se.lejon.customcolumn.Deleted 的成员
    • .filter(_.status =!= (Deleted: Status)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多