在数据访问层中重用Slick的DB驱动程序代码

时间:2016-09-29 17:45:18

标签: scala slick data-access

我试图用Slick 3.0来解决数据访问问题。在咨询了各种github示例后,我发现了以下设计。

注入DataSource和Driver实例的单例Slick对象

class Slick(dataSource: DataSource, val driver: JdbcDriver)  {

  val db = driver.api.Database.forDataSource(dataSource)     

}

每个数据库表中定义映射的特征

特征在构造查询的上层混合。

trait RecipeTable {

  protected val slick: Slick

  // the ugly import that have to be added when Slick API is used
  import slick.driver.api._

  type RecipeRow = (Option[Long], String)

  class RecipeTable(tag: Tag) extends Table[RecipeRow](tag, "recipe") {

    def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
    def name = column[String]("name")

    def * = (id, name)    
  }

  protected val recipes = TableQuery[RecipeTable]    
}

现在有一个明显的缺点,即在每个*Table特征中以及在混合的每个地方我都需要复制导入slick.driver.api._才能拥有所有Slick' s范围内的东西。

这是我想避免的事情。理想情况下,导入只会定义一次并在下游组件中重复使用。

你能否提出一个解决这种重复问题的设计?

我主要受到this示例的启发,但是那里的导入也是重复的。

1 个答案:

答案 0 :(得分:4)

那"丑陋"对于光滑的设计来说,导入实际上是一件好事。但是你的光滑使用方式可以改进如下,

创建一个提供JdbcDriver

的特征
package demo.slick.dbl

trait SlickDriverComponent {
  val driver: JdbcDriver
}

trait SlickDBComponent extends SlickDriverComponent {
  val db: driver.api.Database
}

现在将DAO特征定义为依赖于此特征的特征

package demo.slick.dao

import demo.slick.dbl.SlickDBComponent

trait RecipeDAO { self: SlickDBComponent =>

  import driver.api._

  type RecipeRow = (Option[Long], String)

  class RecipeTable(tag: Tag) extends Table[RecipeRow](tag, "recipe") {

    def id = column[Option[Long]]("id", O.PrimaryKey, O.AutoInc)
    def name = column[String]("name")

    def * = (id, name)    
  }

  val recipes = TableQuery[RecipeTable]

  def get5Future = db.run(recipes.take(5).result)

}

实际连接数据库和做事时,

package demo.slick.dbl

trait MySqlDriverProvider extends SlickDriverComponent {          
  val driver = slick.driver.MySQLDriver
}

object MySqlDBConnection extends MySqlDriverProvider {
  val connection = driver.api.Database.forConfig("mysql")
}

trait MySqlDBProvider extends SlickDBComponent {          
  val driver = slick.driver.MySQLDriver
  val db: Database = MySqlDBConnection.connection
}

trait PostgresDriverProvider extends SlickDriverComponent {          
  val driver = slick.driver.PostgresDriver
}

object PostgresDBConnection extends PostgresDriverProvider {
  val connection = driver.api.Database.forConfig("postgres")
}

trait PostgresDBProvider extends SlickDBComponent {
  val driver = slick.driver.PostgresDriver
  val db: Database = PostgresDBConnection.connection
}

现在最终定义你的DAO对象,如下所示,

package demo.slick.dao

import demo.slick.dbl.MySqlDBProvider

object MySqlRecipeDAO extends RecipeDAO with MySqlDBProvider

object PostgresRecipeDAO extends RecipeDAO with PostgresDBProvider

现在,您可以按如下方式使用这些,

pakcage demo.slick

import scala.util.{Failure, Success, Try}
import scala.concurrent.ExecutionContext.Implicits.global

import demo.slick.RecipeDAO

object App extends Application {
  val recipesFuture = MysqlRecipeDAO.get5Future

  recipesFuture.onComplete({
    case Success(seq) => println("Success :: found :: " + seq)
    case Failure(ex) => println("Failure :: failed :: " + ex.getMessage)
  })
}

现在......我们都知道不同的数据库具有不同的功能集,因此它们具有不同的功能。可供选择取决于使用的驱动程序。

因此,每次都需要进行丑陋的导入,以便您可以编写一次DAO特征,然后将它们用于您想要的任何数据库特定的驱动程序实现。