短縮版
私は現在、MySQL の照合に関する問題と、それが一連の値にどのように影響するかを調査しています (これは Hibernate を使用してマップされますが、今のところ問題にはなりません)。MySQL が使用するのと同じ照合順序を使用して文字列のセットが必要です。たとえば、「foobar」と「fööbar」は等しいと見なされますが、「foo bar」と「foobar」は異なると見なされます。デフォルトのCollator.getInstance()を ( Collator.PRIMARY強度で) 使用しても、まだ違いがあるため (最も顕著な空白)、確実には機能しません。では、可能なすべての文字列に対して MySQL と同じように動作する Collator を取得するにはどうすればよいでしょうか?
ロングバージョン
セットの値を格納するテーブルに一意のインデックスを作成し、セットが DB で許可されている値のみを保持するようにし、その逆も同様にしたいと考えています。
表は次のようになります。
CREATE TABLE `MY_SET` (
`entity_id` int NOT NULL,
`value` varchar(255) NOT NULL,
UNIQUE `entity-value`(`entity_id`, `value`)
) ENGINE = InnoDB DEFAULT CHARSET=latin1 DEFAULT COLLATION=;
ここで、プレーンな文字列と HashSet を使用して値を保持すると、たとえば次のようになります。
public class MyValues {
private MyEntity _myEntity;
private final HashSet<String> _values = new HashSet<String>();
}
「foobar」と「fööbar」の両方を値のセットに追加することができます。Hibernate が Set を DB にフラッシュすると、MySQL は、定義された「entity-value」キーの「foobar」と「fööbar」が重複していると文句を言います。したがって、文字列をラップし、Collatorを使用して文字列が等しいかどうかをチェックすると考えました。
public class MyValues {
private MyEntity _entity;
private final HashSet<CollatedString> _values = new HashSet<CollatedString>();
}
public static class CollatedString {
private String _string;
private CollationKey _key;
public String getString() {
return _string;
}
public void setString(final String string) {
_string = string;
_key = getCollator().getCollationKey(_string);
}
@Override
public int hashCode() {
return _key.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof CollatedString)) {
return false;
}
return _key.equals(((CollatedString) obj)._key);
}
}
これは、「foobar」と「fööbar」でうまく機能します。
final MyEntity e = new MyEntity();
final MyValues v = new MyValues();
v.setEntity(e);
v.getValues().add(new CollatedString("foobar"));
v.getValues().add(new CollatedString("fööbar"));
System.out.println("1 == " + v.getValues().size()); // prints 1 == 1
ただし、MySQL が異なると見なす "foo bar" と "foobar" では機能しません。
v.getValues().add(new CollatedString("foobar"));
v.getValues().add(new CollatedString("foo bar"));
System.out.println("2 == " + v.getValues().size()); // prints 2 == 1 (which is wrong)
基本的に、あとはgetCollator()メソッドを実装するだけです。
public static final Collator getCollator() {
// FIXME please help!
}
サンプルの完全なコードを入手できます:ダウンロード