2016-05-20 33 views
1

我有一個DAO輔助特徵,可提供通用功能的DAO。它需要能夠訪問表查詢並運行操作。我無法定義或以其他方式將查詢類型提供給助手特徵。上界爲油滑3.1.1查詢類型

下面是一些代碼,在很短的demo project on GitHub也可在action分支。

trait DBComponent { 
    import slick.driver.JdbcProfile 

    val driver: JdbcProfile 
    import driver.api._ 

    val db: Database 
} 

的類被保留延長HasId

trait HasId { 
    def id: Option[Int] = None 
} 

這裏是一個這樣的類被保留:

case class BankInfo(
    owner: String, 
    branches: Int, 
    bankId: Int, 
    override val id: Option[Int] = None 
) extends HasId 

問題 首先,db在性狀DBComponent定義是我不知道如何設置QueryType在以下DAO幫手特質;我預計大多數後面的錯誤是不當類型的結果,我用:

/** Handles all actions pertaining to HasId or that do not require parameters */ 
trait DbAction[T <: HasId] { this: DBComponent => 
    import driver.api._ // defines DBIOAction 

    type QueryType <: slick.lifted.TableQuery[Table[T]] // this type is wrong! What should it be? 
    def tableQuery: QueryType 

    // Is this defined correctly? 
    def run[R](action: DBIOAction[R, NoStream, Nothing]): Future[R] = db.run { action } 

    def deleteById(id: Option[Long]): Unit = 
    for { i <- id } run { tableQuery.filter(_.id === id).delete } // id is unknown because QueryType is wrong 

    def findAll: Future[List[T]] = run { tableQuery.to[List].result } // also b0rked 

    // Remaining methods shown on GitHub 
} 

僅供參考,這裏是如何在上述將被使用。首先,定義表查詢的特點:

trait BankInfoTable extends BankTable { this: DBComponent => 
    import driver.api._ 

    class BankInfoTable(tag: Tag) extends Table[BankInfo](tag, "bankinfo") { 
    val id  = column[Int]("id", O.PrimaryKey, O.AutoInc) 
    val owner = column[String]("owner") 
    val bankId = column[Int]("bank_id") 
    val branches = column[Int]("branches") 

    def bankFK = foreignKey("bank_product_fk", bankId, bankTableQuery)(_.id) 

    def * = (owner, branches, bankId, id.?) <> (BankInfo.tupled, BankInfo.unapply) 
    } 

    val tableQuery = TableQuery[BankInfoTable] 

    def autoInc = tableQuery returning tableQuery.map(_.id) 
} 

這一切都在這裏匯聚:

trait BankInfoRepositoryLike extends BankInfoTable with DbAction[BankInfo] 
{ this: DBComponent => 

    import driver.api._ 

    @inline def updateAsync(bankInfo: BankInfo): Future[Int] = 
    run { tableQuery.filter(_.id === bankInfo.id.get).update(bankInfo) } 

    @inline def getByIdAsync(id: Int): Future[Option[BankInfo]] = 
    run { tableQuery.filter(_.id === id).result.headOption } 
} 

建議?

+0

看看[這個例子](https://gist.github.com/lshoo/9785645) – Sky

+0

看起來很有趣。我想嘗試一下,但現在我已經離開了我的電腦。任何機會,你可以分叉我的項目,並顯示你的代碼? –

+0

現在,我看對了一下代碼,我覺得這是油滑2.1.x的代碼,也不會用油滑3.1.x.工作使用Slick 2.1.x更簡單 - 我有類似的東西,然後工作。這是一個Slick 3.1.x問題,不幸的是 –

回答

1

你試圖抽象的過度的結果類型與HasId但你的代碼實際上並不關心這個。該id值,您使用的是那些從解除類型,即錶行類,所以你需要在這個級別的抽象:

trait LiftedHasId { 
    def id: slick.lifted.Rep[Int] 
} 
DbAction

然後:

type QueryType <: slick.lifted.TableQuery[_ <: Table[T] with LiftedHasId] 

而且BankInfoTable必須定義一個具體類型爲它:

type QueryType = slick.lifted.TableQuery[BankInfoTable] 

或者你可以將其添加爲的第二類型參數DbAction(就像Query具有用於提升型結果類型2級類型的參數)。

+0

感謝@szeiger – Sky

+0

感謝@szeiger,你幫了但還是兩個問題:錯誤在[第71行](https://github.com/mslinn/slick-starting-on-the-right-foot/blob/action/src/main/scala/com/knol/db/repo/BankInfoRepository.scala# L71-L75)和[關於運行的問題](https://github.com/mslinn/slick-starting-on-the-right-foot/blob/action/src/main/scala/com/knol/db/回購/ BankInfoRepository.scala#L23-L24) –

+0

想@szeiger我看到代碼,顯示了第二個類型參數是如何工作的 –

2

全部工作示例:

package com.knol.db.repo 

import com.knol.db.connection.DBComponent 
import com.knol.db.connection.MySqlDBComponent 
import scala.concurrent.{Await, Future} 
import concurrent.duration.Duration 

trait LiftedHasId { 
    def id: slick.lifted.Rep[Int] 
} 

trait HasId { 
    def id: Option[Int] 
} 

trait GenericAction[T <: HasId]{this: DBComponent => 
    import driver.api._ 

    type QueryType <: slick.lifted.TableQuery[_ <: Table[T] with LiftedHasId] 

    val tableQuery: QueryType 

    @inline def deleteAsync(id: Int): Future[Int] = db.run { tableQuery.filter(_.id === id).delete } 
    @inline def delete(id: Int): Int = Await.result(deleteAsync(id), Duration.Inf) 

    @inline def deleteAllAsync(): Future[Int] = db.run { tableQuery.delete } 
    @inline def deleteAll(): Int = Await.result(deleteAllAsync(), Duration.Inf) 

    @inline def getAllAsync: Future[List[T]] = db.run { tableQuery.to[List].result } 
    @inline def getAll: List[T] = Await.result(getAllAsync, Duration.Inf) 

    @inline def getByIdAsync(id: Int): Future[Option[T]] = 
    db.run { tableQuery.filter(_.id === id).result.headOption } 

    @inline def getById(id: Int): Option[T] = Await.result(getByIdAsync(id), Duration.Inf) 

    @inline def deleteById(id: Option[Int]): Unit = 
    db.run { tableQuery.filter(_.id === id).delete } 

    @inline def findAll: Future[List[T]] = db.run { tableQuery.to[List].result } 




} 
trait BankInfoRepository extends BankInfoTable with GenericAction[BankInfo] { this: DBComponent => 

    import driver.api._ 

    type QueryType = TableQuery[BankInfoTable] 

    val tableQuery=bankInfoTableQuery 

    def create(bankInfo: BankInfo): Future[Int] = db.run { bankTableInfoAutoInc += bankInfo } 

    def update(bankInfo: BankInfo): Future[Int] = db.run { bankInfoTableQuery.filter(_.id === bankInfo.id.get).update(bankInfo) } 

    /** 
    * Get bank and info using foreign key relationship 
    */ 
    def getBankWithInfo(): Future[List[(Bank, BankInfo)]] = 
    db.run { 
     (for { 
     info <- bankInfoTableQuery 
     bank <- info.bank 
     } yield (bank, info)).to[List].result 
    } 

    /** 
    * Get all bank and their info.It is possible some bank do not have their product 
    */ 
    def getAllBankWithInfo(): Future[List[(Bank, Option[BankInfo])]] = 
    db.run { 
     bankTableQuery.joinLeft(bankInfoTableQuery).on(_.id === _.bankId).to[List].result 
    } 
} 

private[repo] trait BankInfoTable extends BankTable{ this: DBComponent => 

    import driver.api._ 

    class BankInfoTable(tag: Tag) extends Table[BankInfo](tag, "bankinfo") with LiftedHasId { 
    val id = column[Int]("id", O.PrimaryKey, O.AutoInc) 
    val owner = column[String]("owner") 
    val bankId = column[Int]("bank_id") 
    val branches = column[Int]("branches") 
    def bank = foreignKey("bank_product_fk", bankId, bankTableQuery)(_.id) 
    def * = (owner, branches, bankId, id.?) <> (BankInfo.tupled, BankInfo.unapply) 

    } 

    protected val bankInfoTableQuery = TableQuery[BankInfoTable] 

    protected def bankTableInfoAutoInc = bankInfoTableQuery returning bankInfoTableQuery.map(_.id) 

} 

object BankInfoRepository extends BankInfoRepository with MySqlDBComponent 

case class BankInfo(owner: String, branches: Int, bankId: Int, id: Option[Int] = None) extends HasId 
+0

欲瞭解更多信息,請查看[博客文章](https://blog.knoldus.com/2016/01/01/best-practices-for-using-slick-on-production/comment-page-1/ #comment-28979) – Sky

+0

Hector,您的博客文章由於多個問題而無法編譯。請分叉我的回購,並將您的代碼放在那裏。 –

+0

它是編譯和運行的代碼。你可以從[這裏](https://github.com/satendrakumar06/generic-slick) – Sky