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模式进行比较
我的计划:
现在,正如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 => ... )
...