gpt4 book ai didi

scala - 光滑的通用且与驱动程序无关

转载 作者:行者123 更新时间:2023-12-02 04:06:10 25 4
gpt4 key购买 nike

基本上我想要实现的是以下组合:

Slick 3.0.0 database agnostismSlick 3 reusable generic repository

事实上,我尝试了很多,但我根本无法让它发挥作用。

abstract class BaseModel[T <: slick.lifted.AbstractTable[_]](query: TableQuery[T], val driver: JdbcProfile, val dbTableName: String)
{
lazy val all: TableQuery[T] = TableQuery[T]
import driver.api._

def createTable = all.schema.create
def dropTable = all.schema.create

abstract class BaseTable[B](val tag: Tag) extends Table[B](tag, dbTableName)
{
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
}
}

现在我们已经遇到了问题:

def createTable = all.schema.createdropTable... 相同 -> schema 无法在这里解析,尽管我之前导入驱动程序。

但是当我将其子类化时,一个更大的问题出现了:

这是代码

class NodeModel(driver: JdbcProfile, dbTableName: String) extends BaseModel[NodeTable](TableQuery[NodeTable], driver, dbTableName) {

val dbDriver = driver
import dbDriver.api._

class NodeTable(tag: Tag) extends BaseTable[Node](tag)
{
override def * = id.? <> (Node, Node.unapply)
}

//lazy val all: TableQuery[NodeTable] = TableQuery[NodeTable]
def createTable: DBIO[Unit] = all.schema.create
def dropTable: DBIO[Unit] = all.schema.drop
def insert(node: Node) = all += node
}

这显然不会编译,因为我无法将 NodeTable 作为 T 传递,但给出了我想要实现的目标的想法。

你知道如何解决这个问题吗?我还尝试使用伴随对象,将 BaseTable 移出 BaseModel 并尝试加载 simpleDriver...但它看起来像该功能在最近的版本中已从 Slick 中删除:(

最佳答案

与数据库无关,代码高度可重用

我将 SlickPlayframework 一起使用,这就是我实现数据库无关和通用存储库的方法。

请注意,这项工作的灵感来自 Active Slick

我希望在我的 case 类 上定义像这样的基本增删改查操作。我应该能够执行countupdatedeletecreate。我想只编写一次 curd 代码并永远重用它。

这是演示这一点的代码片段。

case class Dog(name: String, id: Option[Long] = None)
Dog("some_dog").save()
Dog("some_dog").insert()
Dog("some_dog", Some(1)).delete()

CrudActions.scala

import slick.backend.DatabaseConfig
import slick.driver.JdbcProfile

import scala.concurrent.ExecutionContext


trait CrudActions {
val dbConfig: DatabaseConfig[JdbcProfile]
import dbConfig.driver.api._

type Model

def count: DBIO[Int]

def save(model: Model)(implicit ec: ExecutionContext): DBIO[Model]

def update(model: Model)(implicit ec: ExecutionContext): DBIO[Model]

def delete(model: Model)(implicit ec: ExecutionContext): DBIO[Int]

def fetchAll(fetchSize: Int = 100)(implicit ec: ExecutionContext): StreamingDBIO[Seq[Model], Model]
}

现在让我们将实体放入图片中。请注意,Entity 只是我们的案例类

Entity 是我们进行增删改查操作的case class。为了定位我们的实体,我们还需要准备好IdId 对于在数据库中定位和操作实体或记录非常重要。还有Id实体的唯一身份

EntityActionsLike.scala

import slick.backend.DatabaseConfig
import slick.driver.JdbcProfile

import scala.concurrent.ExecutionContext

trait EntityActionsLike extends CrudActions {
val dbConfig: DatabaseConfig[JdbcProfile]
import dbConfig.driver.api._

type Entity

type Id

type Model = Entity

def insert(entity: Entity)(implicit ec: ExecutionContext): DBIO[Id]

def deleteById(id: Id)(implicit ec: ExecutionContext): DBIO[Int]

def findById(id: Id)(implicit ec: ExecutionContext): DBIO[Entity]

def findOptionById(id: Id)(implicit ec: ExecutionContext): DBIO[Option[Entity]]
}

现在让我们实现这些方法。为了进行操作,我们需要 TableTableQuery。假设我们有 tabletableQuery。特征的好处是我们可以声明一个契约并将实现细节留给子类或子类型

EntityActions.scala

import slick.ast.BaseTypedType
import slick.backend.DatabaseConfig
import slick.driver.JdbcProfile

import scala.concurrent.ExecutionContext

trait EntityActions extends EntityActionsLike {
val dbConfig: DatabaseConfig[JdbcProfile]
import dbConfig.driver.api._

type EntityTable <: Table[Entity]

def tableQuery: TableQuery[EntityTable]

def $id(table: EntityTable): Rep[Id]

def modelIdContract: ModelIdContract[Entity,Id]

override def count: DBIO[Int] = tableQuery.size.result

override def insert(entity: Entity)(implicit ec: ExecutionContext): DBIO[Id] = {
tableQuery.returning(tableQuery.map($id(_))) += entity
}

override def deleteById(id: Id)(implicit ec: ExecutionContext): DBIO[Int] = {
filterById(id).delete
}

override def findById(id: Id)(implicit ec: ExecutionContext): DBIO[Entity] = {
filterById(id).result.head
}

override def findOptionById(id: Id)(implicit ec: ExecutionContext): DBIO[Option[Entity]] = {
filterById(id).result.headOption
}

override def save(model: Entity)(implicit ec: ExecutionContext): DBIO[Entity] = {
insert(model).flatMap { id =>
filterById(id).result.head
}.transactionally
}

override def update(model: Entity)(implicit ec: ExecutionContext): DBIO[Entity] = {
filterById(modelIdContract.get(model)).update(model).map { _ => model }.transactionally
}

override def delete(model: Entity)(implicit ec: ExecutionContext): DBIO[Int] = {
filterById(modelIdContract.get(model)).delete
}

override def fetchAll(fetchSize: Int)(implicit ec: ExecutionContext): StreamingDBIO[Seq[Entity], Entity] = {
tableQuery.result.transactionally.withStatementParameters(fetchSize = fetchSize)
}

def filterById(id: Id) = tableQuery.filter($id(_) === id)

def baseTypedType: BaseTypedType[Id]

protected implicit lazy val btt: BaseTypedType[Id] = baseTypedType

}

ActiveRecord.scala

import slick.dbio.DBIO

import scala.concurrent.ExecutionContext


abstract class ActiveRecord[R <: CrudActions](val repo: R) {
def model: repo.Model
def save()(implicit ec: ExecutionContext): DBIO[repo.Model] = repo.save(model)
def update()(implicit ec: ExecutionContext): DBIO[repo.Model] = repo.update(model)
def delete()(implicit ec: ExecutionContext): DBIO[Int] = repo.delete(model)
}

ModelContract.scala

case class ModelIdContract[A, B](get: A => B, set: (A, B) => A)

如何使用

示例.scala

import com.google.inject.{Inject, Singleton}
import play.api.db.slick.DatabaseConfigProvider
import slick.ast.BaseTypedType
import slick.backend.DatabaseConfig
import slick.driver.JdbcProfile
import slick.{ActiveRecord, EntityActions, ModelIdContract}

case class Dog(name: String, id: Option[Long] = None)

@Singleton
class DogActiveRecord @Inject() (databaseConfigProvider: DatabaseConfigProvider) extends EntityActions {

override val dbConfig: DatabaseConfig[JdbcProfile] = databaseConfigProvider.get[JdbcProfile]

import dbConfig.driver.api._

override def tableQuery = TableQuery(new Dogs(_))

override def $id(table: Dogs): Rep[Id] = table.id

override def modelIdContract: ModelIdContract[Dog, Id] = ModelIdContract(dog => dog.id.get, (dog, id) => dog.copy(id = Some(id)))

override def baseTypedType: BaseTypedType[Id] = implicitly[BaseTypedType[Id]]

override type Entity = Dog
override type Id = Long
override type EntityTable = Dogs

class Dogs(tag: Tag) extends Table[Dog](tag, "DogsTable") {
def name = column[String]("name")
def id = column[Long]("id", O.PrimaryKey)
def * = (name, id.?) <> (Dog.tupled, Dog.unapply)
}

implicit class ActiveRecordImplicit(val model: Entity) extends ActiveRecord(this)

import scala.concurrent.ExecutionContext.Implicits.global

val result = Dog("some_dog").save()

val res2 = Dog("some_other_dog", Some(1)).delete()

val res3 = Dog("some_crazy_dog", Some(1)).update()
}

现在我们可以像这样直接对 Dog 进行操作

Dog("some_dog").save()

这种隐式对我们来说很神奇

implicit class ActiveRecordImplicit(val model: Entity) extends ActiveRecord(this)

您还可以在 EntityActions 中添加方案创建和删除逻辑

tableQuery.schema.create
table.schema.drop

关于scala - 光滑的通用且与驱动程序无关,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39499435/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com