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

查看:17
本文介绍了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)

因此,如果我们可以即时获得 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天全站免登陆