问题描述
我正在尝试为Slick 2.0编写通用的CRUD特性.特质应该 a)提供通用方法来读取/更新/删除实体以及 b)从数据库中提取.以下这个精巧的示例(数据库抽象)和本文(CRUD特性),我想出了以下(缩短的)代码片段:
I am trying to write a generic CRUD trait for Slick 2.0. The trait should a) provide generic methods to read/update/delete entities as well as b) abstract from the database. Following this slick example (database abstraction) and this article (CRUD trait) I came up with the following (shortened) code snippet:
trait Profile {
val profile: JdbcProfile
}
trait Crud[T <: AbstractTable[A], A] { this: Profile =>
import profile.simple._
val qry: TableQuery[T]
def countAll()(implicit session: Session): Int = {
qry.length.run
}
def getAll()(implicit session: Session): List[A] = {
qry.list // <-- type mismatch; found: List[T#TableElementType] required: List[A]
}
}
由于类型不匹配,代码无效.第二个函数的返回类型似乎为List[T#TableElementType]
类型,但必须为List [A].关于如何解决问题的任何想法.也欢迎您提供有关Slick 2.0通用操作的进一步阅读的其他参考.
The code is invalid due to a type mismatch. The return type of the 2nd function seems to be of type List[T#TableElementType]
but needs to be List[A]. Any ideas on how to solve the issue. Additional references to further readings on generic Slick 2.0 operations are welcome too.
推荐答案
type TableElementType
是class AbstractTable[A]
内部的抽象. Scala不知道A
和TableElementType
之间的任何关系.另一方面,class Table
定义了final type TableElementType = A
,它向Scala告知了这种关系(显然,Scala足够聪明,可以使用final
注释来知道即使Table[A]
是在A
中不是协变的.)
type TableElementType
is abstract inside of class AbstractTable[A]
. Scala doesn't know about any relationship between A
and TableElementType
. class Table
on the other hand defines final type TableElementType = A
, which tells Scala about this relationship (and apparently Scala is smart enough to use the final
annotation to know that the relationanship even holds for a subtype T <: Table[A]
eventhough Table[A]
is not co-variant in A
).
因此,您需要使用T <: Table[A]
而不是T <: AbstractTable[A]
.并且由于Table
位于Slick驱动程序蛋糕中(如蛋糕模式一样),因此您也需要将Crud移入蛋糕中.蛋糕是病毒.
So you need to use T <: Table[A]
instead of T <: AbstractTable[A]
. And because Table
is inside the Slick driver cake (as in cake pattern), you need to move your Crud into your cake as well. Cakes are viral.
trait Profile {
val profile: JdbcProfile
}
trait CrudComponent{ this: Profile =>
import profile.simple._
trait Crud[T <: Table[A], A] {
val qry: TableQuery[T]
def countAll()(implicit session: Session): Int = {
qry.length.run
}
def getAll()(implicit session: Session): List[A] = {
qry.list // <-- works as intended
}
}
}
这篇关于使用Slick 2.0的通用CRUD操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!