2016-09-29 112 views
2

我试图围绕使用Slick 3.0进行数据访问的过程。在咨询了各种github示例之后,我已经采用了以下设计。在数据访问层中重用Slick的数据库驱动程序代码

其中DataSource和驱动程序实例被注入

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

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

} 

每DB表A中的性状,其中的映射被定义

这种特点就是在上层中,其中混合的单油滑对象查询被构造。

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._才能有所有油滑的东西,在范围混合的地方。

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

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

我主要受this例子的启发,但是这里的进口也是重复的。

回答

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特征,然后能够将它们用于您想要的任何特定于数据库的驱动程序实现。

+0

感谢您的全面回答。虽然我怀疑重复''import driver.api._''实际上是一件好事,但它似乎是与Slick一起使用的唯一方法。当然,必须有这样的参数来设计API,但我仍然不明白为什么只有'TableQuery [T]'实例不足以构建查询(考虑到支持标准SQL结构由*所有*驱动程序)。 –

+0

那么......当你使用'java.time.ZoneDateTime'时,你必须把它导入到你需要的地方......它的原理是一样的。 Slick的大部分内部都被设计为'implicits',可以在需要时导入或更改,而不会影响其他任何东西。 –

相关问题