【问题标题】:Access database column names from a Table?从表中访问数据库列名?
【发布时间】:2013-11-15 00:55:36
【问题描述】:

假设我有a table:

object Suppliers extends Table[(Int, String, String, String)]("SUPPLIERS") {
  def id = column[Int]("SUP_ID", O.PrimaryKey)
  def name = column[String]("SUP_NAME")
  def state = column[String]("STATE")
  def zip = column[String]("ZIP")
  def * = id ~ name ~ state ~ zip
}

表的数据库名称

可以通过以下方式访问表的数据库名称:Suppliers.tableName
Scaladoc on AbstractTable 支持这一点。

例如,上表的数据库名称为“SUPPLIERS”。

列的数据库名称

查看AbstractTablegetLinearizedNodesindexes 看起来很有希望。但是,它们的字符串表示形式中没有列名。

我假设 * 表示 "all the columns I'm usually interested in." * 是一个 MappedProjection,它有这个签名:

final case class MappedProjection[T, P <: Product](
  child: Node, 
  f: (P) ⇒ T, 
  g: (T) ⇒ Option[P])(proj: Projection[P]) 
extends ColumnBase[T] with UnaryNode with Product with Serializable

*.getLinearizedNodes 包含一个巨大的数字序列,我意识到此时我只是在对 API 中的所有内容进行强力检查,以便可能在字符串中找到列名。

以前有没有人遇到过这个问题,或者谁能让我更好地了解 MappedProjection 的工作原理?

【问题讨论】:

    标签: scala slick


    【解决方案1】:

    它要求您依赖 Slick 内部结构,这可能会在版本之间发生变化,但这是可能的。以下是 Slick 1.0.1 的工作原理:您必须通过 FieldSymbol。然后你就可以像columnInfo(driver: JdbcDriver, column: FieldSymbol): ColumnInfo 那样提取你想要的信息了。

    要从Column 获取FieldSymbol,您可以使用fieldSym(node: Node): Option[FieldSymbol]fieldSym(column: Column[_]): FieldSymbol

    【讨论】:

    • 我怎样才能从ColumnBase 得到Column(这里想到*)?或者来自AbstractTableNode
    • Column 是 ColumnBase 的子类。不确定您要做什么。由于它需要 Slick 内部,因此需要自己深入研究 Slick(使用源代码),而且它不是一个稳定的 API。
    • 在给定原始表而不是克隆表的情况下,试图获取表中每个列的类型。只成功地获得了一个 Seq[Node],我能够从中提取 FieldSymbols。不确定如何提取包含在 FieldSymbol 中的 TypeMapper 的类型,并且不想继续将反射作为选项。给定映射到列的索引和要比较的值,该类型将用于推断列的默认过滤器运算符。换句话说,泛化对 query.filter() 的调用
    【解决方案2】:

    要获取(限定)列名,您只需执行以下操作:

    Suppliers.id.toString
    Suppliers.name.toString
    Suppliers.state.toString
    Suppliers.zip.toString
    

    没有明确说明toString 将产生列名,因此您的问题是有效的。


    现在,如果您想以编程方式获取所有列名,那就有点困难了。您可以尝试使用反射来获取所有返回Column[_] 的方法并在它们上调用toString,但这并不优雅。或者你可以稍微破解一下,从这样的查询中得到一个select * SQL 语句:

    val selectStatement = DB withSession {
      Query(Suppliers).selectStatement
    }
    

    然后解析我们的列名。

    这是我能做的最好的。如果有人知道更好的方法,请分享-我也很感兴趣;)

    【讨论】:

    • Thought @krivachy.akos 想知道弹出的另一个答案,来自 Slick 的开发者
    【解决方案3】:

    代码基于 Lightbend Activator “slick-http-app”。

    光滑版本:3.1.1

    在BaseDal中添加了这个方法:

    def getColumns(): mutable.Map[String, Type] = {
      val columns = mutable.Map.empty[String, Type]
    
      def selectType(t: Any): Option[Any] = t match {
        case t: TableExpansion => Some(t.columns)
        case t: Select => Some(t.field)
        case _ => None
      }
      def selectArray(t:Any): Option[ConstArray[Node]] = t match {
        case t: TypeMapping => Some(t.child.children)
        case _ => None
      }
      def selectFieldSymbol(t:Any): Option[FieldSymbol] = t match {
        case t: FieldSymbol => Some(t)
        case _ => None
      }
    
      val t = selectType(tableQ.toNode)
      val c = selectArray(t.get)
    
      for (se <- c.get) {
        val col = selectType(se)
        val fs = selectFieldSymbol(col.get)
        columns += (fs.get.name -> fs.get.tpe)
      }
      columns
    }
    

    此方法从 TableQ 中获取列名(DB 中的真实名称)+ 类型

    使用的进口是:

         import slick.ast._
         import slick.util.ConstArray
    

    【讨论】:

    • 版本控制链接和/或提及您的代码目标的 Slick 版本会有用
    • 感谢您为其他阅读本文的人更新版本!
    猜你喜欢
    • 1970-01-01
    • 2018-05-10
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    相关资源
    最近更新 更多