Scala 将数据库架构与现有slick表进行比较

Scala 将数据库架构与现有slick表进行比较,scala,slick,Scala,Slick,我正在使用Scala、Slick和Postgres构建一个应用程序。我使用了Slick code generator来生成Slick表 我想知道是否有任何方法来验证数据库表模式和slick表模式是否匹配,并对我的应用程序中的所有slick表进行验证 例如: class DepartmentTable(_tableTag: Tag) extends Table[Department](_tableTag, Some("base"), "Department") { val id: Rep[

我正在使用
Scala
Slick
Postgres
构建一个应用程序。我使用了
Slick code generator
来生成Slick表

我想知道是否有任何方法来验证数据库表模式和slick表模式是否匹配,并对我的应用程序中的所有slick表进行验证

例如:

class DepartmentTable(_tableTag: Tag) extends Table[Department](_tableTag, Some("base"), "Department") {
    val id: Rep[Long] = column[Long]("DepartmentId", O.AutoInc, O.PrimaryKey)
    val name: Rep[String] = column[String]("Name", O.Length(50,varying=true))
    val shortCode: Rep[String] = column[String]("ShortCode", O.Length(50,varying=true))
    def * = ???
    def ? = ???
} 
我更改了数据库表,比如在表中添加一列
parentDepartmentId
,然后将其添加到Slick表中。很多时候,出现了alter脚本不能在测试数据库上运行的问题,因此我们会遇到一些运行时异常

为了避免这些问题,我尝试实现一些东西来检查slick表是否与实际的postgres表匹配。这是可以实现的吗

我试着思考,但无法从光滑的桌子上获得所有细节。例如:实际的列名

Slick Version : 3.0
我正在努力实现什么?

在应用程序启动时,我想将数据库模式与slick模式进行比较

我的计划:

  • 从我的应用程序中获取所有TableQuery/Slick表

  • 使用Slick Meta获取实际的数据库模式

  • 将slick tablequery结构与实际数据库进行比较


  • 现在,正如Maxim所建议的,我可以创建一个注册表并将每个表添加到注册表中。我只是想看看还有没有别的办法。原因是,如果我或其他人无意中删除了向注册表添加两个表查询,则不会对该表进行检查。我只是想更安全一些,但不确定是否存在这样的方法

    您可以使用
    slick.meta
    来实现这一点。您并不是说您使用的是哪个版本的slick,所以我将展示一个使用slick 3.0的示例,但是如果您使用slick 2.x将
    DBIO
    替换为旧的
    with session
    API,并删除对
    ExecutionContext
    Future
    的引用,则应该非常类似

    在这里,您可以打印模式中每个表的所有列,假设范围中有一个隐式的
    ExecutionContext
    ,导入
    YourDriver.api.\u
    ,并用实际的
    数据库实例替换

    val db: Database = ???
    
    val tablesWithCols = for {
      tables <- slick.jdbc.meta.MTable.getTables
      withCols <- DBIO.sequence(tables.map(t => t.getColumns.map((t, _))))
    } yield withCols
    
    val printLines: DBIO[Seq[String]] = tablesWithCols.map {
      _.map {
        case (t, cs) => s"Table: ${t.name.name} - columns: ${cs.map(_.name).mkString(", ")}"
      }
    }
    
    val res: Future[Seq[String]] = db.run(printLines)
    
    res.foreach(println)
    
    这将为您提供一个类似AST的结构,您可以遍历它以获得所需的定义;结构本身不是很容易遍历,但它应该包含您需要的所有内容


    为了避免这种麻烦,您可以探索的另一种方法是创建一个层来封装光滑定义的生成,并以更易访问的方式公开相关元数据;但是,不确定这是否会给您带来更大的麻烦。

    下面是一个示例,说明如何检测给定的Slick表中,数据库架构中所有列的数量、名称和SQL类型(假定与该表对应)是否等于该表的Slick表描述中的列的数量、名称和SQL类型

    def ?[AT <: AbstractTable[_]](tableQuery: profile.api.TableQuery[AT])
                                 (implicit ec: ExecutionContext) = {
      val table = tableQuery.baseTableRow.create_*.map(c =>
        (c.name, profile.jdbcTypeFor(c.tpe).sqlType)).toSeq.sortBy(_._1)
      MTable.getTables(tableQuery.baseTableRow.tableName).headOption.map(
        _.map{_.getColumns.map(
          _.sortBy(_.name).map(c => (c.name, c.sqlType)) == table
        )}
      ) flatMap (_.head)
    }
    
    使用MTable的以下方法

    getIndexInfo    
    getPrimaryKeys
    getImportedKeys
    
    正如我在摘录中使用
    tableQuery.baseTableRow.create*
    getColumns
    所做的那样

    现在使用此方法,您可以轻松地检查代码中的所有表。唯一真正简单的问题是如何得到他们的名单。说实话,我甚至不明白这怎么会是一个问题,因为这只是一个保持集中注册表的问题,每次在代码中创建表时,您都可以在其中登记表,并且可以查询存储的对象。假设您有这样的
    注册表
    ,方法是
    登记表
    列表表
    ,那么您的工作流将类似

    val departmentTable = TableQuery[DepartmentTable]
    regsitry.enlistTable(departmentTable)
    ...
    val someTable = TableQuery[SomeTableStructureClass]
    regsitry.enlistTable(someTable)   
    ...
    val anotherTable = TableQuery[AnotherTableStructureClass]
    regsitry.enlistTable(anotherTable)   
    ...
    for(table <- regsitry.listTables)
      db run ?(table) map ( columnsAndTypesAreIdentical => ... ) 
    ...
    
    val departmentTable=TableQuery[departmentTable]
    regsitry.industable(部门表)
    ...
    val someTable=TableQuery[SomeTableStructureClass]
    regsitry.industable(someTable)
    ...
    val anotherTable=TableQuery[AnotherTableStructureClass]
    regsitry.industable(另一个表)
    ...
    (表…)
    ...
    


    默认情况下使用的光滑代码生成器。对应的TableQuery值的格式正好是
    val someTable=TableQuery[SomeTableStructureClass]

    ,这样我就可以从数据库中获得实际的架构细节。我已经在做了。然而,我不知道的是如何获得代码中已经存在的光滑表。我需要将MTable与代码中已经存在的表进行比较。我扩展了答案,添加了一些关于从光滑定义中获取数据的内容,如果我在开始时不理解这个问题,请原谅。谢谢。我能得到这个。但问题是我不知道这些光滑的表都是什么,所以我不能做TableQuery[部门]。我应该能够为我的应用程序中所有光滑的表获取TableQuery。但我无法做到这一点。尝试了一点思考,但还是一样。思考?你可能在开玩笑。这只是一个分解代码的问题,以便使用旧的注册表/存储库模式。我怎样才能动态地获得这100个表的“TableQuery[MyTable1]”。我不明白你的意思。你说你有100张漂亮的桌子是什么意思。表(而不是表存根)是根据表描述创建的某个实例。例如,您的DepartmentTable是Departments表和其他metastuff的描述,TableQuery[DepartmentTable]是您实际使用的表的代理)。因此,您有100个对“表”的引用,它们看起来像val table=TableQuery[…]。考虑您的代码,以便在每个VAL定义之后或在任何位置调用registry.enlist(table),然后按照我在回答中所述的方式继续
    getIndexInfo    
    getPrimaryKeys
    getImportedKeys
    
    val departmentTable = TableQuery[DepartmentTable]
    regsitry.enlistTable(departmentTable)
    ...
    val someTable = TableQuery[SomeTableStructureClass]
    regsitry.enlistTable(someTable)   
    ...
    val anotherTable = TableQuery[AnotherTableStructureClass]
    regsitry.enlistTable(anotherTable)   
    ...
    for(table <- regsitry.listTables)
      db run ?(table) map ( columnsAndTypesAreIdentical => ... ) 
    ...