15

たとえば、ステータスが列挙型の PostgreSQL の製品テーブルは次のとおりです。

create type product_status as enum ('InStock', 'OutOfStock');

create table product (
    pid            int primary key default nextval('product_pid_seq'),
    sku            text not null unique,
    name           text not null,
    description    text not null,
    quantity       int not null,
    cost           numeric(10,2) not null,
    price          numeric(10,2) not null,
    weight         numeric(10,2),
    status         product_status not null
);

製品を挿入する典型的な Clojure コードは次のようになります。

(def prod-12345 {:sku "12345"
                 :name "My Product"
                 :description "yada yada yada"
                 :quantity 100
                 :cost 42.00
                 :price 59.00
                 :weight 0.3
                 :status "InStock"})

(sql/with-connection db-spec
   (sql/insert-record :product prod-12345))

ただし、status列挙型であるため、列挙型にキャストせずに通常の文字列として挿入することはできません。

'InStock'::product_status

次のような準備済みステートメントを使用して実行できることはわかっています。

INSERT INTO product (name, status) VALUES (?, ?::product_status)

しかし、準備されたステートメントを使用せずにそれを行う方法はありますか?

4

5 に答える 5

1

Kris Jurkaは、上記で引用した Mike Sherrill の議論に次のように答えました。

url パラメーター stringtype=unspecified [JDBC 接続 URL 内] を使用して、setString を常に varchar ではなく unknown にバインドします。これにより、コードの変更は必要ありません。

Javaでこれを試してみましたが、うまくいくようです。

于 2014-02-12T19:55:38.383 に答える
0

プレーン SQL をバックエンドに渡さない限り、キャストを使用する必要があります。(SQL ステートメントINSERT INTO product (name, status) VALUES ('SomeName', 'InStock');は正常に動作するはずです。)

Tom Lane は、あなたが質問した 1 週間後に pgsql-hackers でこの問題に対処しました。

私の知る限り、これはJDBCの通常のビジネスです。 setString() は、パラメーターが文字列型であることを意味します。実際に必要な型が文字列以外の場合は失敗します。(私は Java の専門家ではありませんが、代わりに setObject を使用することが標準的な回避策であることを思い出すようです。)

列挙型はここで特別な苦労をしていません。私は型システムを弱体化して特別なパスを与えることに反対します。

私たち自身の@CraigRingerがその議論に参加し、今までに何か関連するものを見つけたかもしれません.

于 2013-05-09T01:16:27.990 に答える
0

このブログ投稿では、この問題に適切に対処しています。は、clojure 値を で表される sql 値に変換するメソッドを 1 つだけ持つprotocoljdbcを提供します。ブログ投稿では、フォーム内のキーワードで列挙型を表すことを提案しているため、次のように実装できます。ISQLValuesql-valuePGObject:type/valueISQLValue

(defn kw->pgenum [kw]
  (let [type (-> (namespace kw)
                 (s/replace "-" "_"))
        value (name kw)]
    (doto (PGobject.)
      (.setType type)
      (.setValue value))))

(extend-type clojure.lang.Keyword
  jdbc/ISQLValue
  (sql-value [kw]
    (kw->pgenum kw)))

あなたの例では、次のように製品を挿入します。

(def prod-12345 {:sku "12345"
                 :name "My Product"
                 :description "yada yada yada"
                 :quantity 100
                 :cost 42.00
                 :price 59.00
                 :weight 0.3
                 ;; magic happens here
                 :status :product_status/InStock})

(sql/with-connection db-spec
   (sql/insert-record :product prod-12345))

問題は、データベースを照会するとき、列挙型がキーワードではなく単純な文字列であることです。IResultSetReadColumnこれは、プロトコルを実装することで同様の方法で解決できます。

(def +schema-enums+
  "A set of all PostgreSQL enums in schema.sql. Used to convert
  enum-values back into Clojure keywords."
  ;; add your other enums here
  #{"product_status"})

(extend-type java.lang.String
  jdbc/IResultSetReadColumn
  (result-set-read-column [val rsmeta idx]
    (let [type (.getColumnTypeName rsmeta idx)]
      (if (contains? +schema-enums+ type)
        (keyword (s/replace type "_" "-") val)
        val))))
于 2019-07-23T15:17:07.057 に答える