2016-09-29 7 views
2

Я пытаюсь обернуть голову доступом к данным с помощью Slick 3.0. После консультаций с различными примерами github я пришел со следующим дизайном.Повторное использование кода драйвера DB Slick на уровне доступа к данным

одноэлементный сликовое объект, где экземпляры DataSource и драйвера инъецируют

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 в области.

Этого я бы хотел избежать. В идеале импорт будет определяться только один раз и повторно использоваться в последующих компонентах.

Не могли бы вы предложить дизайн, который обращается к подобному дублированию?

Я был в основном вдохновлен примером, но импорт также дублируется.

ответ

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», которые могут быть импортированы или изменены по мере необходимости, не затрагивая ничего. –