【发布时间】: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