【问题标题】:How to implement Multi-DB Pattern with Slick 3.1 and DDD如何使用 Slick 3.1 和 DDD 实现多数据库模式
【发布时间】:2017-04-11 14:33:50
【问题描述】:

我正在阅读 Debasish Ghosh 的 Functional And Reactive Domain Modeling,我想重构一个 CRUD 应用程序,它实际上已投入生产。 我专注于使用 Reader monad for DI、Repository 模式和 ADT 的第一种方法,用于管理应用程序之间的等价值的应用程序(考虑一个值,某些应用程序以某种方式理解,然后查询它对于另一个系统的等效值)。

Debasish 将存储库模式称为解耦方式,因此,在我的情况下,我需要 Oracle 和 Postgresql 和 H2 的具体实现来进行测试。 我有以下非常简单的实现(基于本书):

基础trait 用于存储库:

trait Repository[A, Id] {

  def query(id: Id): Try[Option[A]]
  def insert(a: A): Try[A]
  def update(a: A): Try[A]
  def delete(a: A): Try[A]

}

等效存储库模块:

trait EquivalenceRepository extends Repository[Equivalence, Long]{

  def query(id: Long): Try[Option[Equivalence]]
  def insert(a: Equivalence): Try[Equivalence]
  def update(a: Equivalence): Try[Equivalence]
  def delete(a: Equivalence): Try[Equivalence]

}

以及使用 Slick 实现的中途具体

class EquivalenceOracleRepository extends EquivalenceRepository {

  def query(id: Long): Try[Option[Equivalence]] = {
    ???
  }

  def insert(a: Equivalence): Try[Equivalence] = {
    ???
  }

  def update(a: Equivalence): Try[Equivalence] = {
    ???
  }

  def delete(a: Equivalence): Try[Equivalence] = {
    ???
  }

}

private[repository] trait EquivalenceOracleDB{
  this: DBComponent =>

  import jdbcProfile.api._

  final case class EquivalenceDTO(
                                    originId: Int,
                                    equivalenceId: Int,
                                    creator: String,
                                    creationDate: Timestamp,
                                    isActive: Boolean
                                  )

  final class EquivalenceTable(tag: Tag) extends Table[Equivalence](tag, "Equivalence"){

    def originId: Rep[Int] = column[Int]("ORIGIN_ID", O.SqlType("NUMBER(10)"))
    def equivalenceId: Rep[Int] = column[Int]("EQUIVALENCE_ID", O.SqlType("NUMBER(10)"))
    def creator: Rep[String] = column[String]("CREATOR", O.SqlType("NUMBER(10)"))
    def creationDate: Rep[Timestamp] = column[Timestamp]("CREATION_DATE", O.SqlType("TIMESTAMP(6)"))
    def isActive: Rep[Boolean] = column[Boolean]("IS_ACTIVE", O.SqlType("VARCHAR2(1)"))

    def pk: PrimaryKey = primaryKey("EQUIVALENCES_PK", (originId, equivalenceId))

    def * : ProvenShape[EquivalenceDTO] =
      (originId, equivalenceId, creator, creationDate, isActive) <> (EquivalenceDTO.tupled, EquivalenceDTO.unapply)

  }

  val table = TableQuery[EquivalenceTable]

}

作为 Oracle 的最后一个具体实现,您可以看到该 trait 需要一个 DBComponent。这是一个特征,其代码继承自实际的生产应用程序,并尝试为每个 DBMS 定义具体的 Slick 配置文件:

这是每个 DBMS 的分析:

trait Profile {
  val jdbcProfile: JdbcProfile
}

object OracleProfile extends Profile {
  override val jdbcProfile: JdbcProfile = OracleDriver
}

object H2Profile extends Profile {
  override val jdbcProfile: JdbcProfile = H2Driver
}

object PostgreSQLProfile extends Profile {
  override val jdbcProfile: JdbcProfile = PostgreSQLProfile.jdbcProfile
}

这是数据库定义:

trait DBComponent {

  val jdbcProfile: JdbcProfile
  import jdbcProfile.api._
  val db: Database

}

trait OracleDB extends DBComponent {
  val logger: Logger = LoggerFactory.getLogger(this.getClass)
  val jdbcProfile: JdbcProfile = OracleProfile.jdbcProfile
}

trait H2DB extends DBComponent {
  val logger: Logger = LoggerFactory.getLogger(this.getClass)
  val jdbcProfile: JdbcProfile = H2Profile.jdbcProfile
}

trait PostgreSQLDB extends DBComponent {
  val logger: Logger = LoggerFactory.getLogger(this.getClass)
  val jdbcProfile: JdbcProfile = PostgreSQLProfile.jdbcProfile
}

但我的疑虑来了:如果我尝试将包含 Slick 基础的 EquivalenceOracleDB 特征混合到 EquivalenceOracleRepository 中,我还需要混合组件,实际上我得到了一个错误:

混音:

class EquivalenceOracleRepository extends EquivalenceRepository with EquivalenceOracleDB{

还有错误:Illegal inheritance, self-type EquivalenceOracleRepository does not conform to DBComponent,因为接口不匹配。所以,我需要一些光:

  • 是否有一个已知的具体 Slick 多数据库实现可以与 Debasish 公开的范例结合使用?
  • 我怎样才能改进我的具体实现的设计,使其符合书中定义的存储库模式,并且不弄乱目前的具体和抽象实现? (保持关注点分开)

我见过the Multi-DB example that Lightbend has,但是,除了未解决的依赖问题之外,它严重依赖于非常冗长的蛋糕模式。我正在努力坚持这本书。

任何帮助将不胜感激。

谢谢

【问题讨论】:

    标签: scala functional-programming domain-driven-design slick ddd-repositories


    【解决方案1】:

    您收到此类错误的原因是您没有混合OracleDB。你应该替换:

    class EquivalenceOracleRepository extends EquivalenceRepository with EquivalenceOracleDB
    

    class EquivalenceOracleRepository extends EquivalenceRepository with EquivalenceOracleDB with OracleDB
    

    现在你会得到一个错误,db 没有定义,所以你应该在某个地方提供它的实现(因为它在DBComponent 中被定义为抽象)。我认为这可以在OracleDB 中完成,这将使该特征变得具体而不是像现在这样抽象。我认为这样您将或多或少符合书中介绍的设计(您有一个描述您的存储库的抽象接口,以及多个具体/生产实现)。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多