【问题标题】:How could I know if a database table is exists in ScalaQuery我怎么知道 ScalaQuery 中是否存在数据库表
【发布时间】:2011-07-23 10:59:41
【问题描述】:

我正在尝试 ScalaQuery,它真的很棒。我可以使用 Scala 类定义数据库表,并轻松查询。

但是我想知道,在下面的代码中,我如何检查一个表是否存在,所以我不会调用 'Table.ddl.create' 两次并在我运行该程序两次时得到异常?

object Users extends Table[(Int, String, String)]("Users") {
    def id = column[Int]("id")
    def first = column[String]("first")
    def last = column[String]("last")
    def * = id ~ first ~ last
}

object Main
{
    val database = Database.forURL("jdbc:sqlite:sample.db", driver = "org.sqlite.JDBC")

    def main(args: Array[String]) {
        database withSession {
            // How could I know table Users is alrady in the DB?
            if ( ??? )  {
                Users.ddl.create
            }
        }
    }
}

【问题讨论】:

    标签: scala scalaquery


    【解决方案1】:

    您可以在您的 DAO impl 中定义以下方法(取自 Slick MTable.getTables always fails with Unexpected exception[JdbcSQLException: Invalid value 7 for parameter columnIndex [90008-60]]),根据您的 db 中是否有已定义的表,该方法为您提供真或假:

        def checkTable() : Boolean = {
            val action = MTable.getTables
            val future = db.run(action)
            val retVal = future map {result =>
              result map {x => x}
            }
    
            val x = Await.result(retVal, Duration.Inf)
    
            if (x.length > 0) {
              true
            } else {
              false
            }
          }
    

    或者,您可以使用 println 方法检查是否存在某些“GIVENTABLENAME”或其他内容:

          def printTable() ={
              val q = db.run(MTable.getTables)
              println(Await.result(q, Duration.Inf).toList(0)) //prints first MTable element
              println(Await.result(q, Duration.Inf).toList(1))//prints second MTable element
              println(Await.result(q, Duration.Inf).toList.toString.contains("MTable(MQName(public.GIVENTABLENAME_pkey),INDEX,null,None,None,None)"))
          }
    

    别忘了添加

        import slick.jdbc.meta._
    

    然后使用通常的@Inject() 从任何地方调用方法。使用 玩 2.4 和玩 1.0.0。

    干杯,

    【讨论】:

      【解决方案2】:

      See also the related discussion here.我个人更喜欢hezamu的建议,并将其扩展如下以保持DRY:

      def createIfNotExists(tables: TableQuery[_ <: Table[_]]*)(implicit session: Session) {
        tables foreach {table => if(MTable.getTables(table.baseTableRow.tableName).list.isEmpty) table.ddl.create}
      }
      

      然后您可以使用隐式会话创建表:

      db withSession {
        implicit session =>
          createIfNotExists(table1, table2, ..., tablen)
      }
      

      【讨论】:

        【解决方案3】:

        这个帖子有点老了,但也许有人会觉得这很有用。我所有的 DAO 都包括:

        def create = db withSession {
            if (!MTable.getTables.list.exists(_.name.name == MyTable.tableName))
                MyTable.ddl.create
        }
        

        【讨论】:

        • 谢谢,太好了。适用于 Slick 2.1.x
        【解决方案4】:

        这是一个完整的解决方案,检查应用程序是否使用 PostGreSQL DB for PlayFramework 启动

        import globals.DBGlobal
        import models.UsersTable
        import org.scalaquery.meta.MTable
        import org.scalaquery.session.Session
        
        import play.api.GlobalSettings
        import play.api.Application
        
        object Global extends GlobalSettings {
        
            override def onStart(app: Application)  {
        
                DBGlobal.db.withSession { session : Session =>
                    import org.scalaquery.session.Database.threadLocalSession
                    import org.scalaquery.ql.extended.PostgresDriver.Implicit._
                    if (!makeTableMap(session).contains("tableName")) {
                        UsersTable.ddl.create(session)
                    }
                }
            }
        
            def makeTableMap(dbsess: Session): Map[String, MTable] = {
                val tableList = MTable.getTables.list()(dbsess)
                val tableMap = tableList.map {
                t => (t.name.name, t)
            }.toMap
                tableMap
            }
        }
        

        【讨论】:

          【解决方案5】:

          ScalaQuery 0.9.4 版在 org.scalaquery.meta 包中包含许多有用的 SQL 元数据包装类,例如 MTable:

          http://scalaquery.org/doc/api/scalaquery-0.9.4/#org.scalaquery.meta.MTable

          在 ScalaQuery 的测试代码中,我们可以看到使用这些类的示例。特别是,请参阅 org.scalaquery.test.MetaTest。

          我编写这个小函数是为了给我一个所有已知表的映射,以表名作为键。

          import org.scalaquery.meta.{MTable}
          def makeTableMap(dbsess: Session) : Map[String, MTable] = {
              val tableList = MTable.getTables.list()(dbsess);
              val tableMap = tableList.map{t => (t.name.name, t)}.toMap;
              tableMap;
          }
          

          所以现在,在创建 SQL 表之前,我可以检查“if (!tableMap.contains(tableName))”。

          【讨论】:

          【解决方案6】:

          使用java.sql.DatabaseMetaData(接口)。根据您的数据库,可能会实现或多或少的功能。

          【讨论】:

          • 所以我想没有 ScalaQuery 方法可以做到这一点?
          • 我什么也没找到,从我找到的 (User extends Table [(tuple of types)]) 来看,我猜目标是使用早期输入。我看不到您如何自己平滑集成动态定义的表,但是我没有经常使用反射,所以也许有一种方法,我只是看不到。文档有点精简。有一些meta-classes,但我没有在wiki或博客中找到如何使用它们的示例。 :)
          • 我也没有找到任何东西。所以我想这就是答案。请注意,Session#metaData 可以获取当前数据库会话的 java.sq.DatabaseMetaData。
          猜你喜欢
          • 1970-01-01
          • 2018-03-21
          • 2012-09-21
          • 1970-01-01
          • 2021-12-03
          • 2011-11-23
          • 1970-01-01
          • 2011-04-28
          • 2022-10-06
          相关资源
          最近更新 更多