9

我正在尝试 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
            }
        }
    }
}
4

6 回答 6

8

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))”。

于 2011-08-29T03:31:19.673 回答
7

这个线程有点旧,但也许有人会觉得这很有用。我所有的 DAO 都包括:

def create = db withSession {
    if (!MTable.getTables.list.exists(_.name.name == MyTable.tableName))
        MyTable.ddl.create
}
于 2013-04-07T11:39:48.070 回答
2

这是一个完整的解决方案,它使用 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
    }
}
于 2012-05-30T13:28:11.220 回答
1

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

于 2011-03-26T11:52:14.050 回答
0

另请参阅此处的相关讨论。我个人更喜欢 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)
}
于 2014-09-20T16:53:34.177 回答
0

您可以在您的 DAO impl 中定义以下方法(取自Slick MTable.getTables 总是失败并出现意外异常 [JdbcSQLException: Invalid value 7 for parameter columnIndex [90008-60]]),根据是否定义了 true o false数据库中的表:

    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() 从任何地方调用这些方法。使用 play 2.4 和 play-slick 1.0.0。

干杯,

于 2015-09-29T16:20:52.007 回答