2016-09-29 3 views
2

Slick 3.0을 사용하여 데이터 액세스와 관련된 문제를 해결하려고합니다. 다양한 github 예제를 살펴본 후, 저는 다음과 같은 디자인을했습니다.데이터 액세스 레이어에서 Slick의 DB 드라이버 코드 재사용

데이터 소스 및 드라이버 인스턴스

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

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

} 

매핑이 특성은 상층 곳에서 혼합

정의된다 DB 테이블 당 형질 주입되는 싱글 슬릭 개체 쿼리가 생성됩니다.

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

"못생긴"가져 오기는 실제로 slick의 디자인에 대한 좋은 점입니다. 그러나 매끄러운 사용의 당신의 방법은,

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) 

} 

JdbcDriver

package demo.slick.dbl 

trait SlickDriverComponent { 
    val driver: JdbcDriver 
} 

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

지금이 특성에 따라 특성로 DAO의 특성을 정의 제공하는 특성을 만들고, 다음과 같은 개선 될 수있다 실제로 DB와 연결하여 일을 수행하게됩니다.

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 
} 

이제 마지막으로 다음과 같이 다음과 같이 다음을 사용할 수 있습니다, 지금

package demo.slick.dao 

import demo.slick.dbl.MySqlDBProvider 

object MySqlRecipeDAO extends RecipeDAO with MySqlDBProvider 

object PostgresRecipeDAO extends RecipeDAO with PostgresDBProvider 

당신의 DAO 객체를 정의, 우리 모두가 서로 다른 데이터베이스 기능의 다른 세트를 가지고 있음을 알고 이제

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'을 사용하면 필요할 때마다 가져와야합니다 ...그것도 같은 원리입니다. 슬릭의 내부 대부분은 다른 어떤 것에 영향을 미치지 않으면 서 필요할 때마다 가져 오거나 변경할 수있는 '암시 적 (implicits)'으로 설계되었습니다. –

관련 문제