Что происходит с моим соединением SQL в конструкции for? - PullRequest
2 голосов
/ 03 февраля 2011

Я работаю над программой, которая преобразует файлы базы данных питания USDA из ASCII в базу данных sqlite. Информацию об этих файлах можно найти по адресу http://www.ars.usda.gov/Services/docs.htm?docid=8964, что составляет нечто действительно потрясающее.

Однако в приведенном ниже коде мое sql-соединение «исчезает», как только я ввожу конструкцию for в функцию, которая выполняет преобразования.

(defn sanitize-field [field]
  (cond
    (= field "~~") ""
    (= field "") 0
    (and (.startsWith field "~") (.endsWith field "~"))
      (.substring field 1 (- (.length field) 1))
    :default (try
               (Double. field)
               (catch NumberFormatException n 0.0))))


(defn field-separator [line]
  (.split line "\\^"))

(defn parse-file [file]
  (map (fn [l] (map sanitize-field (field-separator l)))
       (.split (slurp (.getCanonicalPath file)) "\r\n")))

(defn convert-food-description [source-dir]
  (println (sql/connection))
  (for [entry (parse-file (File. source-dir "FOOD_DES.txt"))]
    (do
      (println entry)
      (println (sql/connection))
      (sql/insert-rows "food_des" entry))))

(Class/forName "org.sqlite.JDBC")
(def db {:classname "com.sqlite.JDBC" :subprotocol "sqlite" :subname "nutrition.sqlite"})

(defn convert []
  (sql/with-connection db
    (convert-food-description (File. "/home/savanni/Downloads/nutrient_database"))))

Когда я запускаю операцию преобразования, вот что я получаю:

user=> (convert)
(convert)
#<Conn org.sqlite.Conn@180e426>
((01001 0100 Butter, salted BUTTER,WITH SALT   Y  0.0  6.38 4.27 8.79 3.87)
java.lang.Exception: no current database connection

Итак, мои единственные команды println находятся в convert-food-description. Похоже, что первое сразу после запуска функции выполняется нормально, распечатывая соединение, которое я создал с помощью оператора with-connection. Но затем начинается цикл for, я распечатываю первую строку данных, которую я собираюсь вставить в базу данных, а затем выдает исключение при попытке снова напечатать соединение SQL.

Что может быть причиной того, что соединение там исчезает? Что-то еще происходит?

ОБНОВЛЕНИЕ: все sql / функции здесь взяты из clojure.contrib.sql

Ответы [ 2 ]

3 голосов
/ 04 февраля 2011

for ленив.Ваш дескриптор соединения открывается и закрывается на with-connection до того, как for в convert-food-description выполнит оценку.

Вы должны принудительно выполнить оценку, пока дескриптор соединения еще активен.Попробуйте изменить for на doseq, например.

user> (require '(clojure.contrib [sql :as sql]))
nil
user> (import 'org.sqlite.JDBC)
org.sqlite.JDBC
user> (def db {:classname "com.sqlite.JDBC" 
               :subprotocol "sqlite" 
               :subname "foo.sqlite"})
#'user/db
user> (sql/with-connection db (sql/create-table "foo" ["val" "int"]))
(0)

;; Bad
user> (defn foo []
        (sql/with-connection db
          (for [x (range 10)]
            (sql/insert-records "foo" {:val x}))))
#'user/foo
user> (foo)
; Evaluation aborted.
;;java.lang.Exception: no current database connection

;; Good
user> (defn foo []
        (sql/with-connection db
          (doseq [x (range 10)]
            (sql/insert-rows "foo" [x]))))
#'user/foo
user> (foo)
nil
0 голосов
/ 03 февраля 2011

Прежде всего, ваш (println (sql/connection)) не распечатывает ваше текущее соединение. Вместо этого он создает новый и печатает его.

Во-вторых, вы определили дБ как (def db {:classname "com.sqlite.JDBC" :subprotocol "sqlite" :subname "nutrition.sqlite"})

Это не открывает соединение, это просто описание соединения.

В-третьих, вы должны передать db в качестве параметра методу convert-food-description и использовать его для реальных запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...