加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – Slick 3可重用的通用存储库

发布时间:2020-12-16 09:26:49 所属栏目:安全 来源:网络整理
导读:我遇到了使Slick的TableQuery以通用方式使用的问题. 观察常规情况: class AccountRepository {override protected val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)val accounts = TableQuery[Accounts]def all = db.run(accounts.re
我遇到了使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] {

但是,这会产生编译错误:

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]

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

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

但是,我们最终会遇到一个不同的错误:

class type required but T found

在以下地方:

val table = TableQuery[T]

有关解决方案的任何想法?

解决方法

我想如果你能解决tableQuery的初始化问题,那么你可以继续你的GenericRepository.我正在使用Slick 3.0和PostgreSQL.

在slick.lifted.TableQuery中,有一个类似如下的方法

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

因此,如果我们可以动态获取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结合起来,你的问题可能会得到解决.

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读