8

db4oのようなオブジェクト データベースを使用する際に、私が非常に混乱していることの 1 つは、通常は SQL/PL-SQL によって処理される複雑な移行をどのように処理する必要があるかということです。

たとえば、my_users というリレーショナル データベースにテーブルがあるとします。もともと「full_name」という名前の列がありましたが、ソフトウェアが V2 になったので、この列を削除し、フル ネームを空白スペースで分割し、最初の部分を「first_name」という名前の列に入れ、2 番目の部分を列に入れたいと考えています。 last_name という名前です。SQL では、「first_name」列と「second_name」列にデータを入力してから、「full_name」という名前の元の列を削除します。

db4oのようなものでこれを行うにはどうすればよいですか? User.class のすべてのオブジェクトを検索し、first_name と last_name を設定しながら full_name を null に設定するスクリプトを作成する Java プログラムを作成する必要がありますか? 次の svn commit を行うと、full_name に対応するフィールド/bean-property がなくなりますが、これは問題になりますか? 私の「スキーマ」が変更される本番アプリケーションでそれを使用するように思えますが、バージョン x からバージョン x+1 にデータを移行するスクリプトを作成し、バージョン x+2 で実際にしようとしているプロパティを削除します。タイプの一部ではなくなったプロパティを変更する Java スクリプトを作成できないため、バージョン x+1 では削除してください。

問題の一部は、RDBMS が参照しているオブジェクトを単純な大文字と小文字を区別しない文字列ベースの名前に基づいて解決することのようです。Java のような言語では、型付けはこれよりも複雑です。ゲッターがプロパティを参照できない場合/setter/field は実行時にロードされるクラスのメンバーではないため、基本的に同じスクリプトに 2 つのバージョンのコードを含める必要があります (うーん、カスタム クラスローダーは苦痛のように聞こえます)。新しいバージョンのクラスを格納します。別のパッケージ (ごちゃごちゃしているように聞こえます) を使用するか、前述のバージョン x+1 x+2 戦略を使用します (さらに多くの計画が必要です)。おそらく、db4o ドキュメントから収集したことのない明白な解決策があるでしょう。

何か案は?うまくいけば、これはある程度の意味があります。

4

2 に答える 2

10

まず、db4o は、フィールドを自動的に追加または削除するなどの「単純な」シナリオを処理します。フィールドを追加すると、既存のすべてのオブジェクトにデフォルト値が保存されます。フィールドを削除しても、既存のオブジェクトのデータはデータベースに残り、引き続きアクセスできます。フィールドの名前変更などは、特別な「リファクタリング」呼び出しです。

あなたのシナリオでは、次のようなことをします:

  1. フィールド「full_name」を削除し、新しいフィールド「first_name」と「second_name」を追加します
  2. すべての「Address」オブジェクトを反復処理します
  3. 「StoredClass」-API を介して古いフィールドにアクセスします
  4. 値の分割、変更、更新など。新しいフィールドに新しい値を設定し、オブジェクトを保存します。

「Address」クラスがあるとしましょう。「full_name」フィールドは削除されました。ここで、「firstname」と「surname」にそれをコピーしたくありません。次に、次のようになります(Java):

    ObjectSet<Address> addresses = db.query(Address.class);
    StoredField metaInfoOfField = db.ext().storedClass(Address.class).storedField("full_name", String.class);
    for (Address address : addresses) {
        String fullName = (String)metaInfoOfField.get(address);
        String[] splitName = fullName.split(" ");
        address.setFirstname(splitName[0]);
        address.setSurname(splitName[1]);
        db.store(address);
    }

あなたが提案したように、バージョン バンプごとに移行コードを記述します。フィールドがクラスの一部ではなくなった場合、上記のように 'StoredField'-API を使用してアクセスする必要があります。

を使用して、すべての「保存された」クラスのリストを取得できますObjectContainer.ext().storedClasses()StoredClass.getStoredFields()すべてのストア フィールドのリストを取得できるため、そのフィールドがクラスに存在しなくなることはありません。クラスが存在しなくなった場合でも、「GenericObject」クラスを介してオブジェクトを取得してアクセスできます。

更新: 複数のバージョン ステップでデータベースを移行する必要がある、より複雑なシナリオの場合。

たとえば、バージョン v3 では、アドレス オブジェクトがまったく異なって見えます。そのため、v1 から v2 への「移行スクリプト」には、必要なフィールド (私の例では firstname と Surename) がありません。これを処理するには複数の可能性があると思います。

  1. (このアイデアにはJavaを想定しています。確かに.NETにも同等のものがあります)。migration-step をGroovy-scriptにすることができます。そのため、各スクリプトが別のスクリプトに干渉しないようにします。次に、そこで移行に必要なクラスを「クラス」に定義します。したがって、各移行には独自の移行クラスがあります。エイリアスを使用すると、groovy-migration-classes を実際の Java-classes にバインドできます。
  2. 複雑なシナリオのためのリファクタリング クラスの作成。また、このクラスをエイリアスでバインドします。
于 2010-03-10T21:25:38.657 に答える
2

私は人生であまり多くのデータをリファクタリングしなかったので、ここで少しワイルドショットを取っています。

あなたは奇妙な比較をしています: データベースを「ホットマイグレーション」したい場合は、おそらくあなたが説明したx+1バージョンx+2管理アプローチを実行する必要がありますが、私にはよくわかりません-方法がわかりません私はデータベースの専門家ではないので、SQLでこれを行います。

ただし、「コールド」に移行する場合は、古いデータから新しいオブジェクトをインスタンス化し、新しいオブジェクトを保存し、ストア内の各オブジェクトの古いオブジェクトを削除することで、1 つのステップで移行できます。db4o リファレンスを参照してください。

しかし正直なところ、RDBMSでの同じプロセスも複雑です。実際に操作を実行するには、制約チェック(および場合によってはトリガーなど)を無効にする必要があるためです。おそらく、提供した例ではなく、実際のほとんどの場合-世界の事例。やはり、弦の分割は簡単すぎてゲインはほとんどないでしょう。

SQL では、「first_name」列と「second_name」列に入力するだけです

はい、単純な文字列分割操作で簡単に実行できます。しかし、典型的なリファクタリング シナリオでは、SQL では簡単に表現できない、複雑な計算や外部データ ソースが必要になる可能性がある、大規模で複雑な一連のルールに基づいてオブジェクトを再構築します。

そのためには、コードも作成する必要があります。

結局のところ、2 つのプロセスに大きな違いはありません。ライブ データには常に注意を払う必要があり、どちらの場合も確実にバックアップを作成します。リファクタリングは楽しいですが、永続化は難しいため、いずれにせよ同期は困難です。

于 2010-03-10T21:03:34.517 に答える