Ошибка привязки аргументов типа в реализации Slick 3.0 Generic CRUD

Я пытаюсь реализовать общую черту CRUD для игрового приложения Scala. Я следую этой реализации.

Эти мои зависимости -

libraryDependencies ++= Seq(
    "org.postgresql" % "postgresql" % "9.4-1201-jdbc41",
    "com.typesafe.slick" %% "slick" % "3.0.0",
    "com.typesafe.play" %% "play-slick" % "1.0.1",
    "com.typesafe.play" %% "play-slick-evolutions" % "1.0.1",
    "io.spray" %%  "spray-json" % "1.3.2",
    specs2 % Test

)

Это моя общая модель -

package models.generic

import slick.driver.PostgresDriver.api._
import scala.concurrent.Future


abstract class GenericTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
    def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
}

trait GenericCRUD[C <: GenericTable[T], T] extends configs.DBConfig{
    protected val table: TableQuery[C]

    private val queryById = Compiled((id: Rep[Int]) => table.filter(_.id === id))

    def all: Future[Seq[C#TableElementType]] = db.run(table.result)

    def create(c: C#TableElementType): Future[Int] = db.run(table += c)

    def read(id: Int): Future[Option[C#TableElementType]] = db.run(queryById(id).result.headOption)

    def update(id: Int, c: C#TableElementType): Future[Int] = db.run(queryById(id).update(c))

    def delete(id: Int): Future[Int] = db.run(queryById(id).delete)
}

Это реализация модели с использованием универсального -

package models

import java.sql.Timestamp
import scala.concurrent.Future
import slick.driver.PostgresDriver.api._
import generic.{GenericCRUD, GenericTable}


case class Brand(id: Int, name: String, created: Timestamp, updated: Timestamp)

class BrandTable(tag: Tag) extends GenericTable[Brand](tag, "brand") {
    override def id = column[Int]("id", O.PrimaryKey, O.AutoInc)

    def name = column[String]("name")

    def created = column[Timestamp]("created")

    def updated = column[Timestamp]("updated")

    def * = (id, name, created, updated) <>((Brand.apply _).tupled, Brand.unapply)
}

object Brands extends GenericCRUD[Brand, BrandTable] {

    override val table:TableQuery[Brand] = TableQuery[Brand]

}

В настоящее время я получаю следующую ошибку -

play.sbt.PlayExceptions$CompilationException: Compilation error[type arguments [models.Brand] conform to the bounds of none of the overloaded alternatives of
 value apply: [E <: slick.lifted.AbstractTable[_]]=> slick.lifted.TableQuery[E] <and> [E <: slick.lifted.AbstractTable[_]](cons: slick.lifted.Tag => E)slick.lifted.TableQuery[E]]
        at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
        at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
        at scala.Option.map(Option.scala:145) ~[scala-library-2.11.7.jar:na]
        at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:49) ~[na:na]
        at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:44) ~[na:na]
        at scala.Option.map(Option.scala:145) ~[scala-library-2.11.7.jar:na]
        at play.sbt.run.PlayReload$.taskFailureHandler(PlayReload.scala:44) ~[na:na]
        at play.sbt.run.PlayReload$.compileFailure(PlayReload.scala:40) ~[na:na]
        at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) ~[na:na]
        at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) ~[na:na]
        at scala.util.Either$LeftProjection.map(Either.scala:377) ~[scala-library-2.11.7.jar:na]
        at play.sbt.run.PlayReload$.compile(PlayReload.scala:17) ~[na:na]
        at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$2.apply(PlayRun.scala:61) ~[na:na]
        at play.sbt.run.PlayRun$$anonfun$playRunTask$1$$anonfun$apply$2$$anonfun$apply$3$$anonfun$2.apply(PlayRun.scala:61) ~[na:na]
        at play.runsupport.Reloader$$anonfun$reload$1.apply(Reloader.scala:323) ~[na:na]
        at play.runsupport.Reloader$$anon$3.run(Reloader.scala:43) ~[na:na]
        at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_51]
        at play.runsupport.Reloader$.play$runsupport$Reloader$$withReloaderContextClassLoader(Reloader.scala:39) ~[na:na]
        at play.runsupport.Reloader.reload(Reloader.scala:321) ~[na:na]
        at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:113) ~[play-server_2.11-2.4.3.jar:2.4.3]
        at play.core.server.DevServerStart$$anonfun$mainDev$1$$anon$1$$anonfun$get$1.apply(DevServerStart.scala:111) ~[play-server_2.11-2.4.3.jar:2.4.3]
        at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.7.jar:na]
        at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.7.jar:na]
        at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:40) ~[akka-actor_2.11-2.3.13.jar:na]
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397) ~[akka-actor_2.11-2.3.13.jar:na]
        at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) ~[scala-library-2.11.7.jar:na]
        at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) ~[scala-library-2.11.7.jar:na]
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) ~[scala-library-2.11.7.jar:na]
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) ~[scala-library-2.11.7.jar:na]

person ASDF    schedule 24.09.2015    source источник


Ответы (2)


Я нашел ошибку. Я поменял местами общие типы в свойстве GenericCRUD. Вот исправленная версия -

Общая модель:

package models

import java.sql.Timestamp
import scala.concurrent.Future
import slick.driver.PostgresDriver.api._
import generic.{GenericCRUD, GenericTable}


case class Brand(id: Int, name: String, created: Timestamp, updated: Timestamp)

class BrandTable(tag: Tag) extends GenericTable[Brand](tag, "brand") {
    override def id = column[Int]("id", O.PrimaryKey, O.AutoInc)

    def name = column[String]("name")

    def created = column[Timestamp]("created")

    def updated = column[Timestamp]("updated")

    def * = (id, name, created, updated) <>((Brand.apply _).tupled, Brand.unapply)
}

object Brands extends GenericCRUD[BrandTable, Brand] {
    override val table = TableQuery[BrandTable]
}

Реализованная модель:

package models.generic

import slick.driver.PostgresDriver.api._
import scala.concurrent.Future


abstract class GenericTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
    def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
}

trait GenericCRUD[C <: GenericTable[T], T] extends configs.DBConfig{
    protected val table: TableQuery[C]

    private val queryById = Compiled((id: Rep[Int]) => table.filter(_.id === id))

    def all: Future[Seq[C#TableElementType]] = db.run(table.result)

    def create(c: C#TableElementType): Future[Int] = db.run(table += c)

    def read(id: Int): Future[Option[C#TableElementType]] = db.run(queryById(id).result.headOption)

    def update(id: Int, c: C#TableElementType): Future[Int] = db.run(queryById(id).update(c))

    def delete(id: Int): Future[Int] = db.run(queryById(id).delete)
}
person ASDF    schedule 24.09.2015

Я использую эту реализацию CRUD:

https://github.com/jose78/Dashboard-DB/blob/master/src/main/scala/com/github/elx/dashboard/db/TableConf.scala

 trait Crud[M] {
     import slick.lifted.TableQuery

     def generateScript[T , F ](callback:(TableQuery[_]) => String);
     def create(model: M): Any;
     def update(model: M): Future[Int];
     def findByID(id: Long): Future[Option[M]];
     def read(): Future[List[M]];
     def delete(model: M): Future[Int];
     def createTable(): Unit;
}


class CrudImpl[V, M <: DefaultModel[Option[Long]], T <: AbsTable[M]](tableQuery: TableQuery[T]) extends Crud[M] {
     ....    
}

val crudUser: Crud[User] = new CrudImpl[Option[Long], User, UserTable](TableQuery[UserTable]);

Я надеюсь тебе это понравится.

person Jose78    schedule 11.07.2016