我试图用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示例的启发,但是那里的导入也是重复的。
答案 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特征,然后将它们用于您想要的任何数据库特定的驱动程序实现。