【问题标题】:Scala: class type required but {generic type} found in traitScala:需要类类型,但在 trait 中找到 {generic type}
【发布时间】:2015-04-30 16:50:51
【问题描述】:

我正在使用 Slick 3.0 并尝试创建一个特征来提供基本操作。这是我的特点:

object DAO {
  var db: Database = null
}

trait CommonAPI[T <: Table[_]] {
  private val db = DAO.db
  private val objects = TableQuery[T]

  def count: Future[Int] = db.run(objects.length.result)
  def insert(obj: T#TableElementType): Future[Int] = db.run(objects += obj)
  def all: Future[Seq[T]] = db.run(objects.result)
}

DAO.db 在 Play 的 onStart 方法中初始化。但是,我在private val objects = TableQuery[T] 行中遇到了编译错误class type required but T found

我该怎么办?谢谢!

【问题讨论】:

  • 错误出现在哪一行?

标签: scala


【解决方案1】:

这是一种解决方案:

首先,定义它以避免类类型问题..

class Service[T <: Table[_]](path: String, cons: Tag => T){

  lazy val db = Database.forConfig(path)

  def query = TableQuery[T](cons)
}

那么这样使用,Post是Table的子类:

object Abcd {

  object Def extends Service[Post]("mydb", abc) {



    def test = {


      //db

      val q = query.drop(1).take(20)
      val r = db.run(q.result)

      println(q.result.statements.head)
      println(r)

      r

    }
  }

  private def abc(tag: Tag) = new Post(tag)

}

此解决方案测试正常。

【讨论】:

  • 你可以直接写而不是包装对象:object Def extends Service[Post]("mydb", ((tag: Tag) =&gt; new Post(tag)))。或者,您可以传递 TableQuery 而不是标记函数:object Def extends Service[Post]("mydb", (TableQuery[Post]))
【解决方案2】:

您好,我做过类似的事情。我使用了一些不同的方法。我有一个通用 DAO 和几个(每个资源/表)类,它们只是为它继承。

这是通用 DAO:

class BaseDbEntity[T <: BaseEntity, R <: BaseT[T]](val tableName: String, tableQuery: TableQuery[R]) extends DatabaseAccess{

  val createReturningId = tableQuery returning tableQuery.map{item => item.id}

  def create(entity: T): Int = {
    connectionPool withSession {
      implicit session =>
        val resId = createReturningId += entity
        resId
    }
  }

  def getAll = {
    connectionPool withSession {
      implicit session =>
        tableQuery.list
    }
  }
}

全类代码: (https://github.com/vixxx123/scalasprayslickexample/blob/master/src/main/scala/com/vixxx123/scalasprayslickexample/database/BaseDbEntity.scala)

以及具有相应表类的特定DAO:

class PersonDao extends BaseDbEntity[Person, PersonT]("person", TableQuery[PersonT])

class PersonT(tag: Tag) extends BaseT[Person](tag, "person") {
  def name: Column[String] = column[String]("name")
  def lastname: Column[String] = column[String]("lastname")

  override def * = (id.?, name, lastname) <> (
    (Person.apply _).tupled, Person.unapply)
}

您可以在这里找到该课程:https://github.com/vixxx123/scalasprayslickexample/blob/master/src/main/scala/com/vixxx123/scalasprayslickexample/exampleapi/person/PersonDao.scala

也许它会帮助你。

【讨论】:

  • 有没有办法写出我想要的特质?
  • 因此,要使其作为特征工作,您的 objecs val 需要声明为抽象方法 def objects: TableQuery[T] 并且每次混合该特征时,您都必须提供它的实施。第二种方法是您的特征的每个方法都将 tableQuery 作为参数。该参数可能是隐含的 - 所以使用它不会那么痛苦
【解决方案3】:

如果您的表类定义为:

,您可以改为传递标签并从中创建表查询:
case class Sample(....)

class SampleTable(tag: Tag)
  extends Table[Sample](tag, "sample_table") {
    .....
}

然后你可以实现你的通用特征如下:

import scala.slick.driver.MySQLDriver.simple.Tag // here mysql is used , you can import the driver specific to your db

object DAO {
  var db: Database = null
}

trait CommonAPI[T, A<: Table[T]] {
  private val db = DAO.db
  private val tableTag : Tag => A = _
  def setTag(tag : Tag => A) = { tableTag = tag }
  private val objects = TableQuery(tableTag)

  def count: Future[Int] = db.run(objects.length.result)
  def insert(obj: T#TableElementType): Future[Int] = db.run(objects += obj)
  def all: Future[Seq[T]] = db.run(objects.result)
}

【讨论】:

  • tableTag 应该是“var”而不是“val”
猜你喜欢
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 2014-09-26
  • 2021-10-01
  • 1970-01-01
  • 2015-04-03
  • 1970-01-01
相关资源
最近更新 更多