Scala类型内部类的解析

时间:2013-09-05 08:59:29

标签: scala types slick

以下代码显示了一个包含两个Slick表定义的模块(以特征的形式),第二个代码具有对第一个的fk引用。每个表对象都定义一个名为Id的内部案例类,用作其主键。这一切都编译并且工作正常。

trait SlickModule {
  val driver = slick.driver.BasicDriver

  import driver.Table

  case class A(id: TableA.Id, name: String)
  case class B(id: TableB.Id, aId: TableA.Id)

  import scala.slick.lifted.MappedTypeMapper
  implicit val aIdType = MappedTypeMapper.base[TableA.Id, Long](_.id, new TableA.Id(_))
  implicit val bIdType = MappedTypeMapper.base[TableB.Id, Long](_.id, new TableB.Id(_))

  object TableA extends Table[A]("table_a") {
    case class Id(id: Long)

    def id = column[TableA.Id]("id", O.PrimaryKey, O.AutoInc)

    def name = column[String]("name", O.NotNull)

    def * = id ~ name <> (A.apply _, A.unapply _)
  }

  object TableB extends Table[B]("table_b") {
    case class Id(id: Long)

    def id = column[Id]("id", O.PrimaryKey, O.AutoInc)

    def aId = column[TableA.Id]("fk_a", O.NotNull)
    def fkA = foreignKey("fk_a", aId, TableA)(_.id)

    def * = id  ~ aId <> (B.apply _, B.unapply _)
  }
}

但是,如果我从

更改TableA中id的列定义
def id = column[TableA.Id]("id", O.PrimaryKey, O.AutoInc)

通过删除Id的显式路径

def id = column[Id]("id", O.PrimaryKey, O.AutoInc)

我收到以下编译错误:

type mismatch;
  found   : SlickModule.this.TableA.type => scala.slick.lifted.Column[x$5.Id] forSome { val x$5: SlickModule.this.TableA.type }
  required: SlickModule.this.TableA.type =>  scala.slick.lifted.Column[SlickModule.this.TableA.Id]
  Error occurred in an application involving default arguments.
    def fkA = foreignKey("fk_a", aId, TableA)(_.id)
                                   ^

因此,沿着现在包含TableA.type的路径找到aId列的类型参数,而参数恰好是TableA.Id。任何人都可以解释为什么会出现这种差异以及如何在不需要显式引用TableA对象的情况下绕过它?我试图将我的主键列的定义抽象为特征,这个问题阻止我这样做。

我使用的是Scala 2.10.2编译器。

1 个答案:

答案 0 :(得分:1)

我不完全确定为什么您的代码会出现编译错误,但以下内容似乎可以实现您的目标:

trait TableModule {
  import scala.slick.lifted.{MappedTypeMapper, BaseTypeMapper}
  val driver = slick.driver.BasicDriver
  case class Id(id: Long)
  type Row
  abstract class Table(name: String) extends driver.Table[Row](name) {
    def id = column[Id]("id", O.PrimaryKey, O.AutoInc)
    import driver.Implicit._
    def findById(id: Id) = (for (e <- this if (e.id === id)) yield e)
  }
  implicit def idTypeMapper : BaseTypeMapper[Id] = MappedTypeMapper.base[Id, Long](_.id, new Id(_))
}

trait Schema {
  object ModuleA extends TableModule {
    case class Row(id: Id, name: String)
    object table extends Table("table_a") {
      def name = column[String]("name", O.NotNull)
      def * = id ~ name <> (Row.apply _, Row.unapply _)
    }
  }

  object ModuleB extends TableModule {
    case class Row(id: Id, aId: ModuleA.Id)
    object table extends Table("table_b") {
      def name = column[String]("name", O.NotNull)
      def aId = column[ ModuleA.Id]("fk_a", O.NotNull)
      def fkA = foreignKey("fk_a", aId, ModuleA.table)(_.id)
      def * = id  ~ aId <> (Row.apply _, Row.unapply _)
    }
  }
}

object schema extends Schema {
  def main(args: Array[String]): Unit = {
    val ddl = ModuleA.table.ddl ++ ModuleB.table.ddl
    println("Create:")
    ddl.createStatements.foreach(println)
    println("Delete:")
    ddl.dropStatements.foreach(println)
  }
}

特别是与不同表关联的Id类是不同的,所以

val aid = ModuleA.Id(1)
val bid : ModuleB.Id = aid

无法使用

进行编译
[error]  found   : Schema.ModuleA.Id
[error]  required: Schema.ModuleB.Id
[error]     val bid : ModuleB.Id = aid