我遇到了使Slick的TableQuery以通用方式使用的问题。
观察常规情况:
class AccountRepository {
override protected val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
val accounts = TableQuery[Accounts]
def all = db.run(accounts.result)
...
这个想法是将所有可能的内容提取到通用特征或抽象类中,以避免重复。为简单起见,我只包含有问题的代码。
abstract class GenericRepository[T] extends HasDatabaseConfig[JdbcProfile] {
override protected val dbConfig = DatabaseConfigProvider.get[JdbcProfile(Play.current)
val table = TableQuery[T]
}
并使用它:
class AccountRepository extends GenericRepository[Accounts] {
但是,这会产生编译错误:
类型参数[T]符合任何值的重载替代值的界限:[E&lt ;: slick.lifted.AbstractTable []] => slick.lifted.TableQuery [E] [E&lt ;: slick.lifted.AbstractTable []](缺点:slick.lifted.Tag => E)slick.lifted.TableQuery [E]
尝试通过设置边界来解决问题也无济于事。
abstract class GenericRepository[T <: slick.lifted.AbstractTable[T]] extends HasDatabaseConfig[JdbcProfile] {
但是,我们最终会遇到不同的错误:
需要类类型但是找到了
在以下地方:
val table = TableQuery[T]
关于解决方案的任何想法?
答案 0 :(得分:3)
您必须手动传递表查询,
abstract class GenericRepository[T <: slick.lifted.AbstractTable[_]](query: TableQuery[T])
并在实施中,
class AccountRepository extends GenericRepository[Accounts](TableQuery[Accounts])
我希望这能解决你的问题。
答案 1 :(得分:2)
我想如果你能解决tableQuery的初始化,那么你可以继续你的GenericRepository。我正在使用Slick 3.0和PostgreSQL。
在 slick.lifted.TableQuery
中,有一个类似以下的方法
// object TableQuery
def apply[E <: AbstractTable[_]](cons: Tag => E): TableQuery[E] =
new TableQuery[E](cons)
因此,如果我们可以动态获得 instance of E
,那么我们可以获得创建TableQuery的通用方法。因此,反思似乎是解决问题的可能方法。
import scala.reflect.runtime.{ universe => ru }
import slick.lifted.{ AbstractTable, ProvenShape, Tag }
import slick.driver.PostgresDriver.api._
object Reflection {
val runtimeMirror = ru.runtimeMirror(getClass.getClassLoader)
def getTypeTag[T: ru.TypeTag] = ru.typeTag[T]
def createClassByConstructor[T: ru.TypeTag](args: Any*) =
runtimeMirror.reflectClass(getTypeTag[T].tpe.typeSymbol.asClass)
.reflectConstructor(ru.typeOf[T].declaration(ru.nme.CONSTRUCTOR)
.asMethod)(args: _*).asInstanceOf[T]
}
// context bound here is for createClassByConstructor to use
abstract class GenericTableQuery[U, T <: AbstractTable[U]: ru.TypeTag] {
import Reflection._
// look at following code: Students, if you want to initialize Students
// you're gonna need a tag parameter, that's why we pass tag here
val tableQuery = TableQuery.apply(tag => createClassByConstructor[T](tag))
}
// Sample Table
case class Student(name: String, age: Int)
class Students(tag: Tag) extends Table[Student](tag, "students") {
def name = column[String]("name")
def age = column[Int]("age")
override def * : ProvenShape[Student] = (name, age)
<> (Student.tupled, Student.unapply _)
}
// get TableQuery
object TestGenericTableQuery extends GenericTableQuery[Student, Students] {
val studentQuery = tableQuery
}
上面提到的代码只关注通用TableQuery的问题,尝试将它与GenericRepository结合起来,你的问题可能会得到解决。
无论如何,希望它有所帮助。