2

NHibernateでのデータベースのバージョン管理と自動アップグレードに、そこに提案されているほとんどの戦略とは異なる方向からアプローチしたいと思います。

各オブジェクトはXMLマッピングによって定義されているため、各マッピングファイル/構成のサイズとチェックサムを取得し、潜在的なカスタム更新スクリプトとともにドキュメントデータベース(レイヴンなど)に保存したいと思います。スクリプトが見つからない場合は、NHibernateDDLジェネレーターを使用してオブジェクトスキーマを更新します。このようにして変更を検出できます。DDLに加えてDMLの変更を行う必要がある場合、または慎重に順序付けられた変換を実行する必要がある場合は、理論的には制御されたテスト可能な方法で行うことができます。これにより、一定レベルの永続層の不可知論も維持されるはずですが、スクリプトは必ずしもデータベースシステム固有である必要があると思います。

秘訣は、データベースから「古い」マッピングファイルを生成し、それらを現在のマッピングファイルと比較することです。これが可能かどうかはわかりません。また、この戦略を法外に非現実的にする何かが欠けているかどうかもわかりません。

それでは、私の質問です。この戦略はどれほど実用的で、なぜですか。

4

1 に答える 1

5

その問題を解決するために私がしたこと

  1. SchemaVersionというテーブルでデータベースをバージョン管理します
  2. テーブルをクエリして、スキーマが最新であるかどうか(必要なバージョンがDALに格納されているかどうか)を確認します。最新である場合は、6に進みます。
  3. resources / webservices/..からversion==versionFromBbのupdatescriptを取得します。
  4. スキーマバージョンを新しいバージョンに変更するスクリプトを実行します
  5. 後藤2。
  6. アプリを実行する

スクリプトを生成するために私は2つのオプションを使用しました

  1. 1つのrdbmsをサポート:SchemaUpdateを実行してファイルにエクスポートし、DMLステートメントを手動で追加します
  2. 複数のrdbmsをサポート:NhibernateクラスTableを使用して、実行時にddlを生成し、セッションDMLを使用するテーブルとコードを追加/変更/削除します。

アップデート:

「現在のバージョンを保存するためにどのような方法を使用しましたか」

小さな例

このようなもの

public static class Constants
{
    public static readonly Version DatabaseSchemaVersion = new Version(1, 2, 3, 4);
}

public class DBMigration
{
    private IDictionary<Version, Action> _updates = new Dictionary<Version, Action>();
    private Configuration _config;
    private Dialect _dialect;
    private IList<Action<ISession>> _actions = new List<Action<ISession>>(16);
    private string _defaultCatalog;
    private string _defaultSchema;

    private void CreateTable(string name, Action<Table> configuretable)
    {
        var table = new Table(name);
        configuretable(table);

        string createTable = table.SqlCreateString(_dialect, _config.BuildMapping(), _defaultCatalog, _defaultSchema);
        _actions.Add(session => session.CreateSQLQuery(createTable).ExecuteUpdate());
    }

    private void UpdateVersionTo(Version version)
    {
        _actions.Add(session => { session.Get<SchemaVersion>(1).Value = version; session.Flush(); });
    }

    private void WithSession(Action<session> action)
    {
        _actions.Add(action);
    }

    public void Execute(Configuration config)
    {
        _actions.Clear();
        _defaultCatalog = config.Properties[NH.Environment.DefaultCatalog];
        _defaultSchema = config.Properties[NH.Environment.DefaultSchema];
        _config = config;
        _dialect = Dialect.GetDialect(config.Properties);

        using (var sf = _config.BuildSessionFactory())
        using (var session = sf.OpenSession())
        using (var tx = session.BeginTransaction())
        {
            Version dbVersion = session.Get<SchemaVersion>(1).Value;
            while (dbVersion < Constants.DatabaseSchemaVersion)
            {
                _actions.Clear();
                _updates[dbVersion].Invoke(); // init migration, TODO: error handling
                foreach (var action in _actions)
                {
                    action.Invoke(session);
                }
                tx.Commit();
                session.Clear();
                dbVersion = session.Get<SchemaVersion>(1).Value;
            }
        }
    }

    public DBMigration()
    {
        _updates.Add(new Version(1, 0, 0, 0), UpdateFromVersion1);
        _updates.Add(new Version(1, 0, 1, 0), UpdateFromVersion1);
        ...
    }

    private void UpdateFromVersion1()
    {
        AddTable("Users", table => table.AddColumn(...));
        WithSession(session => session.CreateSqlQuery("INSERT INTO ..."));
        UpdateVersionTo(new Version(1,0,1,0));
    }

    ...
}
于 2012-07-12T09:21:36.187 に答える