2016-09-14 56 views
1

基本上我想要實現的是組合:油滑通用和司機無關

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 
} 

這不會明顯地編譯,因爲我無法通過NodeTableT,但給人的想法我想要達到的目標。

你有什麼想法如何解決這個問題嗎?我也試圖與同伴對象,移動BaseTableBaseModel,並試圖加載simpleDriver ...但它看起來就像是從油滑在最近的版本:(

回答

4

數據庫無關刪除的功能和代碼是高度可重複使用的

我使用SlickPlayframework,這是怎麼實現的數據庫無關和通用倉庫。

注意,這項工作從Active油滑

我想有這樣的基本的CRUD操作的啓發,在我的case class定義。我應該可以做到count,update,deletecreate。我想只寫一次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不過是我們的案例類

Entitycase class上,我們做的CRUD操作。爲了定位我們的實體,我們也有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) 

如何使用

Sample.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) 

您還可以添加scheme創建和刪除邏輯EntityActions

tableQuery.schema.create 
table.schema.drop 
從ActiveRectord模式
+0

除了我非常喜歡這一點,會嘗試一下儘快!謝謝你,先生! – Sorona

+0

您還可以提供有關使表定義可擴展的幫助嗎? – Sorona

+0

你將如何實現foreignKeys?就像如果你有一個DogRelation或類似的參考Dog.id – Sorona