我正在尝试为Scala play应用程序实现一个通用的CRUD特性。我遵循这个实现。
这些是我的依赖-
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]
我发现了错误。我交换了泛型类型在GenericCRUD trait中的位置。以下是更正后的版本
通用模型:
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)
}
我正在使用这个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]);
我希望你喜欢。