简体   繁体   English

Clojure:读取数据库的元数据

[英]Clojure: read metadata of a database

I am trying to get metadata from an sqlite database. 我正在尝试从sqlite数据库获取元数据。 The main purpose for the moment was to get a list of tables. 此刻的主要目的是获取表列表。

Code below (from here: link ): 以下代码(来自此处: 链接 ):

(defn db-get-tables
"Demonstrate getting table info"
[]
(sql/with-connection db
   (into []
      (resultset-seq
       (-> (sql/connection)
           (.getMetaData)
           (.getTables nil nil nil (into-array ["TABLE" "VIEW"])))))))

This gives me a list of maps with metadata regarding the tables in the database. 这给了我一张包含有关数据库表的元数据的地图列表。 However, if I try to iterate this list (using 'for' or 'first') it gives me: 但是,如果我尝试遍历此列表(使用“ for”或“ first”),则会得到以下信息:

"Don't know how to create ISeq from proj00.operations.database$tables-list"

I believe that there must be an easy way to do this. 我相信必须有一个简单的方法来做到这一点。 But I just cannot find the right information on the web. 但是我只是无法在网络上找到正确的信息。 Also, I cannot understand where that error is coming from. 另外,我无法理解该错误的来源。

It might be because the connection with the database is only open within the scope of "sql/with connection db". 可能是因为与数据库的连接仅在“ sql / with connection db”的范围内打开。 If I iterate through the collection like this with Microsoft SQL, I get an error that the connection is closed. 如果我使用Microsoft SQL遍历这样的集合,则会收到错误消息,指出连接已关闭。

If you wrap the resultset-seq in a doall, this should be fixed. 如果将结果集序列包装在doall中,则应修复此问题。 This breaks lazyness though in favor of getting all results into memory and being able to close the connection. 尽管这有助于您将所有结果都存储到内存中并能够关闭连接,但是这打破了延迟。 If you want to keep lazyness, you should put the iteration within the "with-connection" scope, but you'll keep the connection open until you're done. 如果要保持惰性,则应将迭代置于“ with-connection”范围内,但要保持连接打开直到完成。

Also, you can generalize this function into supporting all metadata methods by making a macro of this (thanks to Verneri Åberg's answer to a question of mine): 同样,您可以通过对此宏进行宏化(通过VerneriÅberg对我的问题的回答)来支持所有元数据方法:

(defmacro get-sql-metadata [db method & args] 
  `(with-connection 
    ~db 
    (doall 
      (resultset-seq 
        (~method 
          (.getMetaData (connection)) 
          ~@args)))))

So now you can call the metadata with the metadata method and its own parameters like so: 因此,现在您可以使用元数据方法及其自身的参数来调用元数据,如下所示:

(get-sql-metadata db .getTables nil nil nil (into-array ["TABLE" "VIEW"]))
or
(get-sql-metadata db .getColumns nil nil nil nil)

Followup: Created a testdatabase, connected, everything should work like this. 后续:创建一个已连接的测试数据库,一切应按以下方式进行。

Leiningen Leiningen

  (defproject sqlitetest "1.0.0-SNAPSHOT"
    :description "FIXME: write description"
    :dependencies [[org.clojure/clojure "1.3.0"]
                   [org.xerial/sqlite-jdbc "3.6.16"]
                   [org.clojure/java.jdbc "0.1.0"]])

Program 程序

(ns sqlitetest
  (:use [clojure.java.jdbc]))

(def db { :classname "org.sqlite.JDBC"
          :subprotocol "sqlite"
          :subname "E:/temp/chinook.db"})

(defmacro get-sql-metadata [db method & args]
  `(with-connection
    ~db
    (doall
      (resultset-seq
        (~method
          (.getMetaData (connection))
          ~@args)))))

(def tables-list
  (get-sql-metadata db .getTables nil nil nil (into-array ["TABLE" "VIEW"])))

REPL REPL

sqlitetest=>(map :table_name tables-list)
("SQLITE_SEQUENCE" "ALBUM" "ARTIST" "CUSTOMER" "EMPLOYEE" "GENRE" "INVOICE" "INVOICELINE" "MEDIATYPE" "PLAYLIST" "PLAYLISTTRACK" "TRACK")

sqlitetest=>(first tables-list)   
{:self_referencing_col_name nil, :table_name "SQLITE_SEQUENCE", :type_schem nil, :ref_generation nil, :table_type "TABLE", :table_schem nil, :table_cat nil, :type_cat nil, :type_name nil, :remarks nil}

Remark on your comment and answer to the question The error is caused by doing defn instead of def over the table-list as in your comment. 在您的评论上标记并回答问题该错误是由于在评论中对表列表执行defn而不是def而引起的。 I run into the same error if I use defn. 如果使用defn,则会遇到相同的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM