Slick 3可重用的通用存储库 [英] Slick 3 reusable generic repository

查看:80
本文介绍了Slick 3可重用的通用存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了使Slick的TableQuery以通用方式使用的问题.

I am experiencing issues making Slick's TableQuery used in a generic fashion.

观察常规情况:

class AccountRepository {
override protected val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
val accounts = TableQuery[Accounts]
def all = db.run(accounts.result)
...

该想法是将所有可能的内容提取到通用特征或抽象类中,以避免重复.为了简单起见,我仅包含有问题的代码.

The idea would be to extract everything possible into generic trait or abstract class in order to avoid repetition. For the sake of simplicity I included only the problematic code.

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] {

但是,这会导致编译错误:

However, that creates a compilation error:

类型参数[T]不符合任何适用的重载值的界限:[E< ;: slick.lifted.AbstractTable []] => slick.lifted.TableQuery [E] [E] < ;: slick.lifted.AbstractTable []](缺点:slick.lifted.Tag => E)slick.lifted.TableQuery [E]

type arguments [T] conform to the bounds of none of the overloaded alternatives of value apply: [E <: slick.lifted.AbstractTable[]]=> slick.lifted.TableQuery[E] [E <: slick.lifted.AbstractTable[]](cons: slick.lifted.Tag => E)slick.lifted.TableQuery[E]

尝试通过设置边界来解决问题也无济于事.

Trying to fix the issue by setting a boundary doesn't help as well.

abstract class GenericRepository[T <: slick.lifted.AbstractTable[T]] extends HasDatabaseConfig[JdbcProfile] {

但是,我们最终遇到了另一个错误:

However, we end up with a different error:

必需的类类型,但找到了T

class type required but T found

在以下位置:

val table = TableQuery[T]

对解决方案有任何想法吗?

Any idea about the solution?

推荐答案

我想如果您可以解决tableQuery的初始化,那么您可以继续执行GenericRepository.我在PostgreSQL上使用了Slick 3.0.

I guess if you can solve the initialization of tableQuery, then you can continue your GenericRepository. I am using Slick 3.0 with PostgreSQL.

slick.lifted.TableQuery 中,有一种类似于以下的方法

In the slick.lifted.TableQuery, there is a method like the following

// object TableQuery
def apply[E <: AbstractTable[_]](cons: Tag => E): TableQuery[E] =
    new TableQuery[E](cons)

因此,如果我们可以即时获得 instance of E ,那么我们将获得创建TableQuery的通用方法.因此,反思似乎是解决问题的一种可能方法.

So if we can get an instance of E on the fly, then we can get a generic way to create TableQuery. So reflection seems to be a possible way to solve it.

 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结合使用,您的问题可能会得到解决.

The codes mentioned above is just focused on the issue of generic TableQuery, try to combine it with your GenericRepository and your problem may get solved.

无论如何,希望对您有所帮助.

Anyway, hope it helps.

这篇关于Slick 3可重用的通用存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆