Java方法作为带有嵌套方法调用UPDATE的函数中的参数

问题描述

| 我有一个通过clojure-sql获取JDBC元数据的功能
(ns relink
     (:require
      [clojure.contrib.sql :as sql]
      [clojure.string :as str]
      ))

(let [db-host \"localhost\"
      db-port 1433
      db-name \"databasename\"]

(def db {:classname \"com.microsoft.sqlserver.jdbc.sqlServerDriver\"
         :subprotocol \"sqlserver\"
         :subname (str \"//\" db-host \":\" db-port)
         :databasename db-name
         :user \"user\"
         :password \"password\"}))

(defn get-table-Metadata
    \"Take database spec,return all table names from the database Metadata\"
    [db]
    (sql/with-connection db
      (doall
                (resultset-seq                 
                    (.getTables
                      (.getMetaData (sql/connection))
                     nil nil \"%\" (into-array \'(\"TABLE\")))))))

(get-table-Metadata db)
现在,我想通过将该java方法调用包装在clojure函数中作为参数,将该函数扩展为使用其他sql元数据,如下所示:
(get-sql-Metadata db .getTables nil nil \"%\" (into-array \'(\"TABLE\")))
如果不将(.getMetaData(sql / connection))放入函数参数中,似乎也无法完成此操作。
(get-sql-Metadata db #(.getTables (.getMetaData (sql/connection)) nil nil \"%\" (into-array \'(\"TABLE\"))))
但是,我想在get-sql-Metadata函数中对此进行抽象,因为对于所有元数据方法调用而言都是相同的。 我已经尝试用doto,..,->和(。表示法重写resultset-seq中的部分,但它们都不起作用。 我错过了什么 ? 更新: 以下解决方案有效,但是需要一些技巧。我无法相信应该在str-invoke中进行反思,所以我不会将其作为答案。
(defn str-invoke [instance method-str & args]
            (clojure.lang.Reflector/invokeInstanceMethod 
                instance 
                method-str 
                (to-array args)))

(defn get-sql-Metadata
    \"Take database spec,Metadata method (as string) and method parameters\"
    [db method & args]
    (sql/with-connection db
      (doall
                (resultset-seq                 
                   (apply str-invoke
                     (.getMetaData (sql/connection))
                     method args)))))

(get-sql-Metadata db \"getTables\" nil nil \"%\" (into-array \'(\"TABLE\")))
问题似乎是需要应用,但不能在上使用。形成。     

解决方法

        由于将get-sql-metadata设置为函数将导致clojure在应用函数之前先评估参数,因此无法将无法评估的\“ unknown \”符号(如.getTables)传递给该函数。 另一方面,在宏中,在应用宏之前不评估参数。 因此,将函数设置为宏将允许您执行此操作。 喜欢:
(defmacro get-sql-metadata [db method & args] 
  `(with-connection 
    ~db 
    (doall 
      (resultset-seq 
        (~method 
          (.getMetaData (connection)) 
          ~@args)))))
当然,也可以通过使用宏memfn将方法调用转换为clojure函数,但是我不认为这就是您想要的     ,        问题是您正在尝试在对象“ nil”上调用.getTables。删除(.getMetaData(sql / connection))时,您也删除了.getTables消息的接收者。您需要MetaData对象,以便可以在其上调用.getTables方法。您可以将其包装成let:
(let [metadata (.getMetaData (sql/connection))]
  (get-sql-metadata db #(.getTables metatdata nil nil \"%\" (into-array \'(\"TABLE\")))))
更新: 这个怎么样:
(get-sql-metadata db (fn [meta] (.getTables meta nil nil \"%\" (into-array \'(\"TABLE\")))))
然后get-table-metadata变成:
(defn get-table-metadata
  \"Take database spec,return all table names from the database metadata\"
  [db metafunction]
  (sql/with-connection db
    (doall
     (resultset-seq
      (metafunction (.getMetaData (sql/connection)))))))