コード例 #1
0
        public void Migrate(string version)
        {
            EnsureMigrationRecordsExists();

            IEnumerable <IDataMigration> migrations = _dataMigrationDiscoverer.DataMigrations;
            IDataMigration migration = migrations.SingleOrDefault(m => m.Version == version);

            if (migration == null)
            {
                throw new MigrationNullException(version);
            }

            IEnumerable <IDataMigration> readyToUndoMigrations =
                migrations.Where(m => m.TableName == migration.TableName &&
                                 m.Version.CompareTo(version) > 0)
                .OrderByDescending(m => m.Version);

            foreach (IDataMigration m in readyToUndoMigrations)
            {
                m.SchemaBuilder = new SchemaBuilder(_interpreter);
                m.Down();
            }

            DoUpdateMigrationRecord(migration);
        }
コード例 #2
0
        private IEnumerable <OperationsMigration> LoadMirations(IDataMigration instance, int version)
        {
            var type      = instance.GetType();
            var migration = instance as DataMigration;

            if (migration != null)
            {
                InitDataMigration(migration);
            }

            var dbMigration = _reposority.FindMigration(type.FullName);

            if ((dbMigration == null && version == -1) || //卸载
                (dbMigration != null && dbMigration.Version == version))    //版本已经是设置的版本
            {
                return(null);
            }

            if (version == 0) //安装版本设为最大值
            {
                version = int.MaxValue;
            }

            if (dbMigration == null || version > dbMigration.Version)
            {
                return(Upgrade(migration, dbMigration, version));
            }

            if (dbMigration.Version > version)
            {
                return(Downgrade(migration, dbMigration, version));
            }

            return(null);
        }
コード例 #3
0
 private async Task<Records.DataMigration> GetDataMigrationRecordAsync(IDataMigration tempMigration)
 {
     var dataMigrationRecord = await GetDataMigrationRecordAsync();
     return dataMigrationRecord
         .DataMigrations
         .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName);
 }
コード例 #4
0
 private DataMigrationRecord GetDataMigrationRecord(IDataMigration tempMigration)
 {
     return(_contentStorageManager
            .Query <DataMigrationDocument>(x => x != null)
            .SelectMany(x => x.DataMigrationRecords)
            .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName));
 }
コード例 #5
0
        private async Task <DataMigrationRecord?> GetDataMigrationRecordAsync(IDataMigration migration)
        {
            var dataMigrationsDocument = await GetOrCreateDataMigrationsDocumentAsync();

            var records = dataMigrationsDocument.DataMigrations;

            return(records.FirstOrDefault(x => x.DataMigrationClass == migration.GetType().FullName));
        }
コード例 #6
0
        /// <summary>
        /// Returns the CreateAsync method from a data migration class if it's found
        /// </summary>
        private static MethodInfo?GetMethod(IDataMigration dataMigration, string name)
        {
            var flags      = BindingFlags.Public | BindingFlags.Instance;
            var methodInfo = dataMigration.GetType().GetMethod(name, flags);
            var returnType = methodInfo?.ReturnType;

            return(returnType != null && (returnType == typeof(Task <int>) || returnType == typeof(int)) ? methodInfo : null);
        }
コード例 #7
0
 /// <summary>
 /// Create a list of all available Update methods from a data migration class, indexed by the version number
 /// </summary>
 private static Dictionary <int, MethodInfo> CreateUpgradeLookupTable(IDataMigration dataMigration)
 {
     return(dataMigration
            .GetType()
            .GetMethods(BindingFlags.Public | BindingFlags.Instance)
            .Select(GetUpdateMethod)
            .Where(tuple => tuple != null)
            .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2));
 }
コード例 #8
0
        /// <summary>
        /// Returns the UninstallAsync method from a data migration class if it's found
        /// </summary>
        private static MethodInfo GetUninstallAsyncMethod(IDataMigration dataMigration)
        {
            var methodInfo = dataMigration.GetType().GetMethod("UninstallAsync", BindingFlags.Public | BindingFlags.Instance);
            if (methodInfo != null && methodInfo.ReturnType == typeof(Task))
            {
                return methodInfo;
            }

            return null;
        }
コード例 #9
0
        /// <summary>
        /// Returns the Create method from a data migration class if it's found
        /// </summary>
        private static MethodInfo GetCreateMethod(IDataMigration dataMigration)
        {
            var methodInfo = dataMigration.GetType().GetMethod("Create", BindingFlags.Public | BindingFlags.Instance);
            if (methodInfo != null && methodInfo.ReturnType == typeof(int))
            {
                return methodInfo;
            }

            return null;
        }
コード例 #10
0
        public IDataMigrationDiscoverer Add(IDataMigration dataMigration)
        {
            IDataMigration migration = null;

            if (!_internalDataMigrationStore.TryGetValue(dataMigration.Version, out migration))
            {
                _internalDataMigrationStore.Add(dataMigration.Version, dataMigration);
            }
            return(this);
        }
コード例 #11
0
        /// <summary>
        /// Returns the CreateAsync method from a data migration class if it's found
        /// </summary>
        private static MethodInfo GetCreateAsyncMethod(IDataMigration dataMigration)
        {
            var methodInfo = dataMigration.GetType().GetMethod("CreateAsync", BindingFlags.Public | BindingFlags.Instance);

            if (methodInfo != null && methodInfo.ReturnType == typeof(Task <int>))
            {
                return(methodInfo);
            }

            return(null);
        }
コード例 #12
0
        /// <summary>
        /// Returns the Uninstall method from a data migration class if it's found
        /// </summary>
        private static MethodInfo GetUninstallMethod(IDataMigration dataMigration)
        {
            var methodInfo = dataMigration.GetType().GetMethod("Uninstall", BindingFlags.Public | BindingFlags.Instance);

            if (methodInfo != null && methodInfo.ReturnType == typeof(void))
            {
                return(methodInfo);
            }

            return(null);
        }
コード例 #13
0
        private void ActivateDataInitializer()
        {
            Type dataMigrationType = this.DependencyTypes.FirstOrDefault(t => typeof(IDataMigration).IsAssignableFrom(t));

            if (dataMigrationType != null)
            {
                IDataMigration dataMigration = Activator.CreateInstance(dataMigrationType) as IDataMigration;

                this.DataInitializer = new DataInitializer(this, dataMigration);

                this.DataInitializer.Initialize();
            }
        }
コード例 #14
0
        public async Task <string> ExecuteAsync(string recipeFileName, IDataMigration migration)
        {
            var featureInfo = _typeFeatureProvider.GetFeatureForDependency(migration.GetType());

            var recipeBasePath   = Path.Combine(featureInfo.Extension.SubPath, "Migrations").Replace('\\', '/');
            var recipeFilePath   = Path.Combine(recipeBasePath, recipeFileName).Replace('\\', '/');
            var recipeFileInfo   = _hostingEnvironment.ContentRootFileProvider.GetFileInfo(recipeFilePath);
            var recipeDescriptor = await _recipeReader.GetRecipeDescriptor(recipeBasePath, recipeFileInfo, _hostingEnvironment.ContentRootFileProvider);

            recipeDescriptor.RequireNewScope = false;

            var executionId = Guid.NewGuid().ToString("n");

            return(await _recipeExecutor.ExecuteAsync(executionId, recipeDescriptor, new object(), CancellationToken.None));
        }
コード例 #15
0
        protected void DoUpdateMigrationRecord(IDataMigration dataMigration)
        {
            MigrationRecord record = _migrationRecordRepository.Get(m => m.TableName == dataMigration.TableName);

            if (record == null)
            {
                record = new MigrationRecord
                {
                    TableName = dataMigration.TableName
                };
            }

            record.Version = dataMigration.Version;

            Logger.Debug("DataMigrationManager", "Migrate {0} to version:{1}", record.TableName, record.Version);
            _migrationRecordRepository.CreateOrUpdate(record);
        }
コード例 #16
0
        public async Task <string> ExecuteAsync(string recipeFileName, IDataMigration migration)
        {
            var featureInfo = _typeFeatureProvider.GetFeatureForDependency(migration.GetType());

            var recipeBasePath   = Path.Combine(featureInfo.Extension.SubPath, "Migrations").Replace('\\', '/');
            var recipeFilePath   = Path.Combine(recipeBasePath, recipeFileName).Replace('\\', '/');
            var recipeFileInfo   = _hostingEnvironment.ContentRootFileProvider.GetFileInfo(recipeFilePath);
            var recipeDescriptor = await _recipeReader.GetRecipeDescriptor(recipeBasePath, recipeFileInfo, _hostingEnvironment.ContentRootFileProvider);

            recipeDescriptor.RequireNewScope = false;

            var environment = new Dictionary <string, object>();

            await _environmentProviders.OrderBy(x => x.Order).InvokeAsync((provider, env) => provider.PopulateEnvironmentAsync(env), environment, _logger);

            var executionId = Guid.NewGuid().ToString("n");

            return(await _recipeExecutor.ExecuteAsync(executionId, recipeDescriptor, environment, CancellationToken.None));
        }
コード例 #17
0
        private static int PerformMigration(IDataMigration migration, Type migrationType, int nextVersion)
        {
            var migrationMethodVersions =
                migrationType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                             .Where(IsMigrationMethod)
                             .ToDictionary(ExtractAvailableMethodVersion, method => method);

            var allVersionSorted = migrationMethodVersions.Keys.OrderBy(version => version).ToList();

            if (!migrationMethodVersions.Any())
            {
                return NoMigrationsFound;
            }

            var migrationIndex = allVersionSorted.BinarySearch(nextVersion);
            if (migrationIndex < 0)
            {
                return NoMigrationsFound;
            }

            for (var i = migrationIndex; i < allVersionSorted.Count; i++)
            {
                var version = allVersionSorted[i];

                try
                {
                    var methodInfo = migrationMethodVersions[version];
                    if (methodInfo.GetParameters().Any())
                    {
                        throw new InvalidOperationException("Migration method must be parameterless.");
                    }

                    methodInfo.Invoke(migration, new object[0]);
                }
                catch (Exception ex)
                {
                    throw new InvokingMigrationException(version, migrationType.FullName, ex);
                }
            }

            return allVersionSorted.Last();
        }
コード例 #18
0
        private void PerformMigration(IDataMigration migration, MigrationInfo migrationEntity)
        {
            var migrationType = migration.GetType();

            bool newMigration = false;

            if (migrationEntity == null)
            {
                newMigration = true;
                migrationEntity = new MigrationInfo { MigrationName = migration.GetType().FullName, Version = -1 };
            }

            try
            {
                migrationEntity.Version = PerformMigration(migration, migrationType,
                                                           migrationEntity.Version + 1);

                if (migrationEntity.Version == NoMigrationsFound)
                {
                    return;
                }

                if (newMigration)
                {
                    this.storage.New(migrationEntity);
                }
                else
                {
                    this.storage.Update(migrationEntity);
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
コード例 #19
0
 private DataMigrationRecord GetDataMigrationRecord(IDataMigration tempMigration) {
     return _dataMigrationRepository
         .Table
         .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName);
 }
コード例 #20
0
 private Tables.OrmTablesInfo GetDataMigrationRecord(IDataMigration tempMigration)
 {
     return(OrmManager.Read <Tables.OrmTablesInfo>(" DataMigrationClass='" + tempMigration.GetType().FullName + "'").FirstOrDefault());
 }
コード例 #21
0
 private async Task <DataMigration> GetDataMigrationRecordAsync(IDataMigration tempMigration)
 {
     return((await GetDataMigrationRecord()).DataMigrations
            .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName));
 }
コード例 #22
0
 public DataInitializer(IModule module, IDataMigration dataMigration)
 {
     this.Module        = module;
     this.DataMigration = dataMigration;
 }
コード例 #23
0
 private DataMigrationRecord GetDataMigrationRecord(IDataMigration tempMigration)
 {
     return(_dataMigrationRepository
            .Table
            .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName));
 }
コード例 #24
0
 public DataMigrationInterpreter(IDataMigration dataMigrationInvoker, IMigrationMetaStorage storage)
 {
     this.dataMigrationInvoker = dataMigrationInvoker;
     this.storage = storage;
 }
コード例 #25
0
 /// <summary>
 /// Returns the CreateAsync method from a data migration class if it's found
 /// </summary>
 private static MethodInfo?GetCreateAsyncMethod(IDataMigration dataMigration) => GetMethod(dataMigration, "CreateAsync");
コード例 #26
0
        protected void DoUpdateMigrationRecord(IDataMigration dataMigration)
        {
            MigrationRecord record = _migrationRecordRepository.Get(m => m.TableName == dataMigration.TableName);

            if (record == null)
            {
                record = new MigrationRecord
                {
                    TableName = dataMigration.TableName
                };
            }

            record.Version = dataMigration.Version;

            Logger.Debug("DataMigrationManager", "Migrate {0} to version:{1}", record.TableName, record.Version);
            _migrationRecordRepository.CreateOrUpdate(record);
        }
コード例 #27
0
 /// <summary>
 /// Create a list of all available Update methods from a data migration class, indexed by the version number
 /// </summary>
 private static Dictionary<int, MethodInfo> CreateUpgradeLookupTable(IDataMigration dataMigration) {
     return dataMigration
         .GetType()
         .GetMethods(BindingFlags.Public | BindingFlags.Instance)
         .Select(GetUpdateMethod)
         .Where(tuple => tuple != null)
         .ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);
 }
コード例 #28
0
        private async Task UpdateAsync(IDataMigration dataMigration)
        {
            if (_processedMigrations.Contains(dataMigration))
            {
                return;
            }

            var migrationName = dataMigration.GetType().FullName;

            _processedMigrations.Add(dataMigration);
            _logger.LogInformation("Running migration '{MigrationName}'", migrationName);

            // Apply update methods to migration class.

            var schemaBuilder = new SchemaBuilder(_store.Configuration, await _session.BeginTransactionAsync());

            dataMigration.SchemaBuilder = schemaBuilder;

            // Copy the object for the Linq query.
            var tempMigration = dataMigration;

            // Get current version for this migration.
            var dataMigrationRecord = await GetDataMigrationRecordAsync(tempMigration);

            var current = 0;
            var dataMigrationsDocument = await GetOrCreateDataMigrationsDocumentAsync();

            if (dataMigrationRecord != null)
            {
                // Version can be null if a failed create migration has occurred and the data migration record was saved.
                current = dataMigrationRecord.Version ?? current;
            }
            else
            {
                dataMigrationRecord = new DataMigrationRecord {
                    DataMigrationClass = dataMigration.GetType().FullName !
                };

                dataMigrationsDocument.DataMigrations.Add(dataMigrationRecord);
            }

            try
            {
                // Do we need to call Create()?
                if (current == 0)
                {
                    // try to resolve a Create method.
                    var createMethod = GetCreateMethod(dataMigration);

                    if (createMethod != null)
                    {
                        current = (int)createMethod.Invoke(dataMigration, new object[0]) !;
                    }

                    // try to resolve a CreateAsync method.
                    var createAsyncMethod = GetCreateAsyncMethod(dataMigration);

                    if (createAsyncMethod != null)
                    {
                        current = await(Task <int>) createAsyncMethod.Invoke(dataMigration, new object[0]) !;
                    }
                }

                var lookupTable = CreateUpgradeLookupTable(dataMigration);

                while (lookupTable.TryGetValue(current, out var methodInfo))
                {
                    _logger.LogInformation(
                        "Applying migration '{MigrationName}' from version {Version}",
                        migrationName,
                        current);

                    var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;

                    current = isAwaitable
                        ? await(Task <int>) methodInfo.Invoke(dataMigration, new object[0]) !
                        : (int)methodInfo.Invoke(dataMigration, new object[0]) !;
                }

                // If current is 0, it means no upgrade/create method was found or succeeded.
                if (current == 0)
                {
                    return;
                }

                dataMigrationRecord.Version = current;
            }
            catch (Exception ex)
            {
                _logger.LogError(
                    ex,
                    "Error while running migration version {Version} for '{MigrationName}'",
                    current,
                    migrationName);
            }
            finally
            {
                // Persist data migrations
                _session.Save(dataMigrationsDocument);
            }
        }
コード例 #29
0
        /// <summary>
        /// Returns the Uninstall method from a data migration class if it's found
        /// </summary>
        private static MethodInfo GetUninstallMethod(IDataMigration dataMigration) {
            var methodInfo = dataMigration.GetType().GetMethod("Uninstall", BindingFlags.Public | BindingFlags.Instance);
            if (methodInfo != null && methodInfo.ReturnType == typeof(void)) {
                return methodInfo;
            }

            return null;
        }
コード例 #30
0
 private async Task<DataMigration> GetDataMigrationRecordAsync(IDataMigration tempMigration)
 {
     return (await GetDataMigrationRecord()).DataMigrations
         .FirstOrDefault(dm => dm.DataMigrationClass == tempMigration.GetType().FullName);
 }