私はwikiプログラムでSQLiteをデータベースとして使用しています。 wikiページとそれらのページを記述するタグとの間に多対多の関係を作りたいと思います。私はclojure.java.jdbc
を使ってデータベース操作を処理しています。私はページ間の相互参照テーブルに外部キーの制約を適用したいと思います。私はSQLiteサイト(https://www.sqlite.org/foreignkeys.html)の外部キーに関する情報を見て、これが私が望むものだと信じています。clojure.java.jdbcでのClojureでの外部キー制約の使用
(def the-db-name "the.db")
(def the-db {:classname "org.sqlite.JDBC"
:subprotocol "sqlite"
:subname the-db-name})
(defn create-some-tables
"Create some tables and a cross-reference table with foreign key constraints."
[]
(try (jdbc/db-do-commands
the-db false
["PRAGMA foreign_keys = ON;"
(jdbc/create-table-ddl :pages
[[:page_id :integer :primary :key]
;...
[:page_content :text]])
(jdbc/create-table-ddl :tags
[[:tag_id :integer :primary :key]
[:tag_name :text "NOT NULL"]])
(jdbc/create-table-ddl :tags_x_pages
[[:x_ref_id :integer :primary :key]
[:tag_id :integer]
[:page_id :integer]
["FOREIGN KEY(tag_id) REFERENCES tags(tag_id)"]
["FOREIGN KEY(page_id) REFERENCES pages(page_id)"]])])
(catch Exception e (println e))))
ただし、プラグマをオンにしても効果はありません。
(println "Check before:" (jdbc/query the-db ["PRAGMA foreign_keys;"]))
; Transactions on or off makes no difference.
(println "Result of execute!:" (jdbc/execute! the-db
["PRAGMA foreign_keys = ON;"]))
(println "Check after:" (jdbc/query the-db ["PRAGMA foreign_keys;"]))
;=> Check before: ({:foreign_keys 0})
;=> Result of execute!: [0]
;=> Check after: ({:foreign_keys 0})
結果は、ライブラリ(org.xerial/sqliteの-JDBC「3.21.0.1」)があるため、外部キーをサポートするためにコンパイルされたことを示している:だけでプラグマをオンにし、効果を確認するためにしようと
エラーはありませんでしたが、プラグマを設定しようとしても効果はありません。
2012年にJREAのJDBC JREAでthisが見つかりました。それ以降、説明されている変更は実装されていますが、コードはまだ効果がありません。
最後に、2011年にthis postに指摘されたStackoverflowの質問に対するこの回答が見つかりました。これにより、プラグマを設定していたようなものを一緒にまとめることができました。以下のコードは、特別に設定されたConnection
の作成に依存します。以上を踏まえ
(ns example
(:require [clojure.java.jdbc :as jdbc])
(:import (java.sql Connection DriverManager)
(org.sqlite SQLiteConfig)))
(def the-db-name "the.db")
(def the-db {:classname "org.sqlite.JDBC"
:subprotocol "sqlite"
:subname the-db-name})
(defn ^Connection get-connection
"Return a connection to a SQLite database that
enforces foreign key constraints."
[db]
(Class/forName (:classname db))
(let [config (SQLiteConfig.)]
(.enforceForeignKeys config true)
(let [connection (DriverManager/getConnection
(str "jdbc:sqlite:" (:subname db))
(.toProperties config))]
connection)))
(defn exec-foreign-keys-pragma-statement
[db]
(let [con ^Connection (get-connection db)
statement (.createStatement con)]
(println "exec-foreign-keys-pragma-statement:"
(.execute statement "PRAGMA foreign_keys;"))))
、私は上記の表の作成コードを書き直しました:期待通りにテーブルが作成され
(defn create-some-tables
"Create some tables and a cross-reference table with foreign key constraints."
[]
(when-let [conn (get-connection the-db)]
(try
(jdbc/with-db-connection
[conn the-db]
; Creating the tables with the foreign key constraints works.
(try (jdbc/db-do-commands
the-db false
[(jdbc/create-table-ddl :pages
[[:page_id :integer :primary :key]
[:page_content :text]])
(jdbc/create-table-ddl :tags
[[:tag_id :integer :primary :key]
[:tag_name :text "NOT NULL"]])
(jdbc/create-table-ddl :tags_x_pages
[[:x_ref_id :integer :primary :key]
[:tag_id :integer]
[:page_id :integer]
["FOREIGN KEY(tag_id) REFERENCES tags(tag_id)"]
["FOREIGN KEY(page_id) REFERENCES pages(page_id)"]])])
; This still doesn't work.
(println "After table creation:"
(jdbc/query the-db "PRAGMA foreign_keys;"))
(catch Exception e (println e))))
; This returns the expected results.
(when-let [statement (.createStatement conn)]
(try
(println "After creating some tables: PRAGMA foreign_keys =>"
(.execute statement "PRAGMA foreign_keys;"))
(catch Exception e (println e))
(finally (when statement
(.close statement)))))
(catch Exception e (println e))
(finally (when conn
(.close conn))))))
。 clojure.java.jdbc
の機能の中には、依然として望み通りに機能しないものがあります。 (リストの途中でjdbc/query
の呼び出しを見てください。)いつも期待どおりに動作するようにすることは、Javaの相互運用性を取り戻すことが非常に「手動」なようです。そして、データベースとのあらゆるやりとりのように、特別に設定されたConnection
をget-connection
関数が返して使用する必要があるようです。
ClojureでSQLiteに外部キー制約を適用するより良い方法はありますか?
ところで、最後の5〜6年の間、 '(Class/forName(:classname db))'は不要でした。 – DodgyCodeException