NHibernate数据库版本控制:对象级架构和数据升级

时间:2012-07-11 13:59:57

标签: nhibernate version-control

我想从与其中提出的大多数策略不同的方向来处理NHibernate中的数据库版本控制和自动升级。

由于每个对象都是由XML映射定义的,我想为每个映射文件/配置获取大小和校验和,并将其与可能的自定义更新脚本一起存储在文档数据库(raven或其他东西)中。如果未找到脚本,请使用NHibernate DDL生成器更新对象模式。通过这种方式,我可以检测到变化,如果我需要在DDL之外进行DML更改,或者执行仔细排序的转换,理论上我可以以受控的,可测试的方式进行。这也应该保持一定程度的持久层不可知性,尽管我想象脚本仍然必然是数据库系统特定的。

诀窍是,生成" old"从数据库映射文件并将它们与当前映射文件进行比较。我不知道这是否可行。我也不知道我是否遗漏了任何可能使这一策略难以实现的其他内容。

我的问题是:这个策略有多实用,为什么?

1 个答案:

答案 0 :(得分:5)

我做了什么来解决这个问题

  1. 在名为SchemaVersion的表中对数据库进行版本化
  2. 查询表以查看架构是否是最新的(存储在DAL中的必需版本),如果是,请转到6。
  3. 从resources / webservices /...
  4. 获取版本== versionFromBb的updatescript
  5. 运行脚本,该脚本也将schemaversion更改为新版本
  6. 转到2。
  7. 运行应用
  8. 生成我使用了2个选项的脚本

    1. 支持一个rdbms:运行SchemaUpdate导出到文件中并手动添加DML语句
    2. 支持多个rdbms:使用Nhibernate类表在运行时生成ddl以添加/更改/删除使用会话DML的表和代码
    3. 更新

        

      “您使用什么方法存储当前版本”

           

      小例子

      类似这样的事情

      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));
          }
      
          ...
      }