citext
データベース内で使用する大文字と小文字を区別しない演算子を、他の citext 値とともに提供します。
何が起こっていますか
text
推測では、JPA 実装は、パラメーター化されたステートメントを作成するときのように、パラメーターの型を明示的に指定しています。citext
は演算子を定義しないため、citext = text
PostgreSQL は をキャストcitext
しtext
、大文字と小文字を区別するtext = text
演算子を使用します。実際には、との比較citext
でtext
は大文字と小文字が区別されます。
これが私が起こっていると思うことです。ダミーデータが与えられた場合:
regress=# CREATE EXTENSION citext;
regress=# CREATE TABLE citest ( x citext );
regress=# INSERT INTO citest(x) VALUES ('FRED'), ('FrEd');
regress=# SELECT * FROM citest;
x
------
FRED
FrEd
(2 rows)
... citext と不明な文字列リテラルの比較は、citext=citext
大文字と小文字を区別せずに次のように解釈されます。
regress=# SELECT * FROM citest WHERE x = 'FRED';
x
------
FRED
FrEd
(2 rows)
citext
...しかし、 とを明示的にtext
型指定されたリテラルと比較すると、citext
引数がtext
usingcitext
の暗黙的なテキストへのキャストに変換され、大文字とtext=text
小文字を区別する比較が行われます。
regress=# SELECT * FROM citest WHERE x = 'FRED'::text;
x
------
FRED
(1 row)
むしろ、Hibernate が行っていることは次のようになります。
regress=# PREPARE blah(text) AS SELECT * FROM citest WHERE x = $1;
PREPARE
regress=# EXECUTE blah('FRED');
x
------
FRED
(1 row)
Hibernatetext
は文字列がtext
.
つまり、PgJDBC を介して Hibernate を取得し、citext
データ型をクエリのパラメータ型として明示的に指定する必要があります。結果は次のようになります。
regress=# PREPARE blah(citext) AS SELECT * FROM citest WHERE x = $1;
PREPARE
regress=# EXECUTE blah('FRED');
x
------
FRED
FrEd
(2 rows)
citext
準備されたステートメントへの明示的な型パラメーターに注意してください。citext
特にPgJDBCは型について何も知らないので、それは...興味深い...行うことになります。PgJDBC のsetObject
;を使用する Hibernate 用のカスタム データ型ハンドラーを作成する必要があります。それでも、Java と Pg の間で演算子の一貫性の問題が発生します (以下を参照)。
lower()
IMOでは、従来の大文字と小文字を区別するタイプや、ILIKE
などを使用した方がはるかに優れています。
また、Hibernate が、列の大文字と小文字の区別について PgJDBC が伝える内容に依存している可能性もあります。少なくとも 9.2-devel の時点では、PgJDBC はcitext
型について何も認識していないため、尋ねられると常に「はい、大文字と小文字が区別されます」と表示されます。
トレース
JPA によって実行される実際のクエリを見ずに、それが起こっていることを確認することは困難です。で設定log_statement = 'all'
してみてくださいpostgresql.conf
。次にSIGHUP
、postmaster を使用するpg_ctl reload
か、Pg を再起動して、変更を有効にします。
テストを再実行し、ログを調べます。に表示されているクエリをテストしてpsql
、結果を観察します。何が起こっているのかわからない場合は、質問を更新してください。更新する場合は、Hibernate のバージョンと PgJDBC のバージョンも含めてください。
また、Hibernate が、列の大文字と小文字の区別について PgJDBC が伝える内容に依存している可能性もあります。少なくとも 9.2-devel の時点では、PgJDBC はcitext
型について何も認識していないため、尋ねられると常に「はい、大文字と小文字が区別されます」と表示されます。
オペレーターの一貫性の問題
警告:citext
タイプは、Hibernate がデータベースから出てきたテキストをどのように処理するかに影響を与えることはできません。String.equals
たとえば、メソッドには影響しません。テキストの大文字と小文字を区別しないようにHibernateに指示する必要があります。それ以外の場合、text
またはプライマリ/外部キーがある場合、Hibernate が keyをvarchar
要求する状況が発生する可能性があり、返され、DB が (Hibernate によると) 等しくないキーを返したため、かなり混乱します。求められました。エンティティに-backed 文字列と実装を含めると、同様の奇妙なことが発生します。"FRED"
"FrEd"
citext
equals
hashCode
@Column
残念ながら、JPA は、列が大文字と小文字を区別するかどうかについて、マッピングで注釈属性を指定していないようです。いずれにせよ、 Javaには大文字と小文字を区別しない文字列データ型の概念がないため、JPA が指定したとしても、あまり効果がありません。
citext
for キーを使用したり、 andにcitext
値を含めたりしない限り、Hibernate の混乱を避けることができるでしょう。equals
hashCode