4

短縮版

私は現在、MySQL の照合に関する問題と、それが一連​​の値にどのように影響するかを調査しています (これは Hibernate を使用してマップされますが、今のところ問題にはなりません)。MySQL が使用するのと同じ照合順序を使用して文字列のセットが必要です。たとえば、「foobar」と「fööbar」は等しいと見なされますが、「foo bar」と「foobar」は異なると見なされます。デフォルトのCollat​​or.getInstance()を ( Collat​​or.PRIMARY強度で) 使用しても、まだ違いがあるため (最も顕著な空白)、確実には機能しません。では、可能なすべての文字列に対して MySQL と同じように動作する Collat​​or を取得するにはどうすればよいでしょうか?

ロングバージョン

セットの値を格納するテーブルに一意のインデックスを作成し、セットが 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」が重複していると文句を言います。したがって、文字列をラップし、Collat​​orを使用して文字列が等しいかどうかをチェックすると考えました。

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)

基本的に、あとはgetCollat​​or()メソッドを実装するだけです。

public static final Collator getCollator() {
  // FIXME please help!
}

サンプルの完全なコードを入手できます:ダウンロード

4

1 に答える 1

2

私はなんとか自分で何かを動かすことができました。組み込みのCollat​​orsに自分のやりたいことをさせることができなかったので、自分で何かを実装することにしました。調査結果をブログに投稿しました。基本的な考え方は、MySQLの文字セット/照合定義ファイル(私のUbuntuシステムでは/ usr / share / mysql / charsets)を読み取ることでした。別のアプローチは、これらの定義からRuleBasedCollat​​orのルールを作成することでしたが、機能が少ない独自の照合ツールを作成することにしました(MySQL照合では、大文字と小文字を区別するように構成することはできません。ではありません)そして非常にうまく機能するはずです。

于 2009-10-07T17:25:54.460 に答える