2

下面的代码显示了一个包含两个 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)
                                   ^

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

我正在使用 Scala 2.10.2 编译器。

4

1 回答 1

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
于 2013-09-16T03:48:15.117 回答