告诉 scala 编译器类型 TableQuery[T] 可以映射到具有属性 id 的东西的 way/s 是什么
What are the way/s of telling scala compiler that type TableQuery[T] can map to somthing has the attribute id
我希望编译器知道或测试该类型 T 是否具有 属性 id。
def del[T](id: Int) = TableQuery[T] filter (_.id === id) delete
trait T { val id: Int}
您的数据类型应该扩展 T。
您是否要删除所有 id=someId 的那些?
那样的话 filter(_.id === id).foreach(delete)
创建 Entity
特征的 T
子类型并在 Entity
中声明 id
trait Entity {
val id: Int
}
def del[T <: Entity](id: Int) = TableQuery[T] filter (_.id === id) delete
Scala REPL
scala> trait Entity {
| val id: Int
| }
defined trait Entity
scala> def foo[T <: Entity](a: T) = a.id
foo: [T <: Entity](a: T)Int
您可以使用结构类型对类型参数实施约束。
case class Thing(id: Int)
def getId[A <: {val id: Int}](a: A):Int = a.id
println(getId(Thing(100)))
这里的结果是 100
但是,由于结构类型使用反射,因此这种方法会影响性能。
另外,正如 Ian 指出的那样,您需要在 scalaOptions
中打开 -language:reflectiveCalls
。
其他答案在某种程度上是正确的,但我怀疑它们是否适用于 Slick,您的 ID 必须是某个参数的 Rep
而不是 Int
,最好的方法是带有 id 字段的抽象 table 并使您的具体 table 扩展:
abstract class RichTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
val id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)
}
class ConcreteTable(tag: Tag) extends RichTable[ConcreteRow](tag, "concrete_table") { ... }
请注意,我将 id 设为主键。现在任何 TableQuery[T]
和 [T <: RichTable[A], A]
都可以访问一个 id:
trait GenericPersistence[T <: RichTable[A], A] {
val tableReference: TableQuery[T]
def deleteById(id: Long)(implicit s: Session): Boolean =
tableReference.filter(_.id === id).delete == 1
/* other generic methods ids based */
}
有关其他方法的更完整答案,您可以查看 this,对于 Slick 3,它基本相同。
你可以通过以下特征获得相同的结果:
trait RichTable[T] {
self: Table[T] =>
val id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)
}
class ConcreteTable(tag: Tag) extends Table[ConcreteRow](tag, "concrete_table") with RichTable[ConcreteRow]
您可以决定是否要在特征中实现 id 字段。
仅供记录,我也尝试过这个,这似乎有效,但到目前为止我不相信实际代码中的进一步解决方案,因为这与用例相关。
trait TableModel[T <: ({val id: Rep[Int]}) with Table[U], U]{
val tq: TableQuery[T]
def del(id: Int) = tq filter (_.id === id) delete
...
}
我希望编译器知道或测试该类型 T 是否具有 属性 id。
def del[T](id: Int) = TableQuery[T] filter (_.id === id) delete
trait T { val id: Int}
您的数据类型应该扩展 T。
您是否要删除所有 id=someId 的那些?
那样的话 filter(_.id === id).foreach(delete)
创建 Entity
特征的 T
子类型并在 Entity
id
trait Entity {
val id: Int
}
def del[T <: Entity](id: Int) = TableQuery[T] filter (_.id === id) delete
Scala REPL
scala> trait Entity {
| val id: Int
| }
defined trait Entity
scala> def foo[T <: Entity](a: T) = a.id
foo: [T <: Entity](a: T)Int
您可以使用结构类型对类型参数实施约束。
case class Thing(id: Int)
def getId[A <: {val id: Int}](a: A):Int = a.id
println(getId(Thing(100)))
这里的结果是 100
但是,由于结构类型使用反射,因此这种方法会影响性能。
另外,正如 Ian 指出的那样,您需要在 scalaOptions
中打开 -language:reflectiveCalls
。
其他答案在某种程度上是正确的,但我怀疑它们是否适用于 Slick,您的 ID 必须是某个参数的 Rep
而不是 Int
,最好的方法是带有 id 字段的抽象 table 并使您的具体 table 扩展:
abstract class RichTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
val id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)
}
class ConcreteTable(tag: Tag) extends RichTable[ConcreteRow](tag, "concrete_table") { ... }
请注意,我将 id 设为主键。现在任何 TableQuery[T]
和 [T <: RichTable[A], A]
都可以访问一个 id:
trait GenericPersistence[T <: RichTable[A], A] {
val tableReference: TableQuery[T]
def deleteById(id: Long)(implicit s: Session): Boolean =
tableReference.filter(_.id === id).delete == 1
/* other generic methods ids based */
}
有关其他方法的更完整答案,您可以查看 this,对于 Slick 3,它基本相同。
你可以通过以下特征获得相同的结果:
trait RichTable[T] {
self: Table[T] =>
val id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)
}
class ConcreteTable(tag: Tag) extends Table[ConcreteRow](tag, "concrete_table") with RichTable[ConcreteRow]
您可以决定是否要在特征中实现 id 字段。
仅供记录,我也尝试过这个,这似乎有效,但到目前为止我不相信实际代码中的进一步解决方案,因为这与用例相关。
trait TableModel[T <: ({val id: Rep[Int]}) with Table[U], U]{
val tq: TableQuery[T]
def del(id: Int) = tq filter (_.id === id) delete
...
}