1

私は、allocationSize=25 の TableGenerator を持つ JPA エンティティを持っています。TableGenerator テーブルを手動で更新して、次の ID 開始範囲の新しい値を指定した場合、現在の範囲が過ぎるまで効果がありません。

たとえば、現在の TableGenerator テーブル値が 10 の場合、250、251、252 などのエンティティ ID を取得し始めます。255 で、TableGenerator テーブル値を 20 に変更します。ただし、次の ID は 256 のままです。 、257、274 まで次の ID は 500 になります。

もちろん、これは当然のことですが、Hibernate に現時点で現在の間隔を無視して、TableGenerator テーブルにあるものから ID の割り当てを開始するように指示する方法はあるのでしょうか?


したがって、大きな理由に答えるために、私の特定のケースでは:

私は、チームの製品用のテスト自動化ツールに取り組んでいます。これは、実行中のシステム (クライアント アプリケーション、API などを使用) を介してテスト データをセットアップできるものです。テスト データ構成 (テストデータと呼びましょう) は、特定のテスト ケース/テスト スイートに対して複数のテストデータを一緒に使用できるように定義されています。

これで、testdata が実行されると、ツールは入力されたデータを db から SQL 挿入ステートメントに抽出し、それらをファイルに格納します。これにはいくつかの理由がありますが、主にパフォーマンスに関するものです。特定のテストデータで100のテストケースを実行したい場合、テストデータが「手動で」1回挿入されることだけを本当に気にします。リセットするたびに、テスト データをデータベースに直接挿入するという、はるかに高速な方法を使用できます。

ただし、前述したように、複数のテストデータを一緒に使用することもできます。testdata01 と testdata02 の両方が同じテーブルに影響する場合はどうなるでしょうか? 抽出された SQL 挿入ステートメントには、別のテストデータが事前に実行されている場合、その特定のテストデータのみのデータは含まれません。

これに対する簡単な解決策は、テストデータごとに ID の間隔を確保することです。各テーブルについて、testdata01 には間隔 [10000, 20000)、testdata02 には間隔 [20000, 30000) などがあります。これは簡単に実装できます。各 testdata を実行する前に、すべての TableGenerator テーブルを testdata の ID 間隔の下限に更新するだけです。次に、testdata セットアップを実行した後、間隔内の ID を持つ行のみを抽出します。

これはうまく機能し、テストデータ間で ID の競合が発生しないようにし、各テストデータのエクスポートされた SQL には、その時点でデータベースに他に何があるかに関係なく、その特定のテストデータのデータのみが含まれるようにします。ただし、allocationSize が 1 ではないこの 1 つのことが混乱を招きます。エンティティの TableGenerator を更新したにもかかわらず、エントリが特定のエンティティの予約済み ID 間隔外に表示される場合があります。

要するに、私がやりたいことは、TableGenerator テーブルを更新した後、testdata セットアップの実行を開始する前に、Hibernate に各エンティティについて、次に ID を生成するときに次のものを無視するように指示したいということです。その TableGenerator の範囲から生成したい値を選択し、代わりにデータベース内の TableGenerator テーブルをチェックして、次にどの範囲を使用するかを確認します。

4

1 に答える 1

1

だから私は自分でこれをスクラッチすることができました。誰かが同じ必要性を持っている場合の将来の参考のために:

public void moveToNextInterval(Class entity, javax.persistence.EntityManager em) throws IllegalAccessException, InstantiationException {
    javax.persistence.TableGenerator tableGenerator = null;
    for (Method method : entity.getMethods()) {
        tableGenerator = method.getAnnotation(javax.persistence.TableGenerator.class);
        if (tableGenerator != null) {
            break;
        }
    }
    if (tableGenerator != null && tableGenerator.allocationSize() > 1) {
        int allocationSize = tableGenerator.allocationSize();
        org.hibernate.impl.SessionImpl session = (org.hibernate.impl.SessionImpl) em.unwrap(org.hibernate.Session.class);
        IdentifierGenerator idGenerator = session.getFactory().getIdentifierGenerator(entity.getName());
        while ((Long)idGenerator.generate(session, entity.newInstance()) % allocationSize != allocationSize - 1);
    }
}

Hibernate や JPA にはまだあまり慣れていないので、おそらく多くの改善の可能性があります。これをあらゆる種類のシーケンスジェネレーターで一般化することはそれほど難しくありません。また、エンティティのインスタンスを 1 つ作成して再利用するだけでよい場合もあります。さらに、意図した ID をオーバーシュートするリスクがあると思います。たとえば、allocationSize=25 で最後の ID が 24 で、TableGenerator テーブルを更新して 10 に設定した場合、このメソッドを呼び出すと、次の ID が 250 ではなく 275 になるようになります。私の目的には十分ですが、知っておくとよいでしょう。

于 2013-08-16T14:20:08.420 に答える