예제 #1
0
        public DatabaseOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] AssemblyLoader startupAssemblyLoader,
            [NotNull] Assembly startupAssembly,
            [CanBeNull] string environment,
            [NotNull] string projectDir,
            [NotNull] string contentRootPath,
            [NotNull] string rootNamespace)
        {
            Check.NotNull(startupAssemblyLoader, nameof(startupAssemblyLoader));
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotNull(startupAssembly, nameof(startupAssembly));
            Check.NotNull(projectDir, nameof(projectDir));
            Check.NotEmpty(contentRootPath, nameof(contentRootPath));
            Check.NotNull(rootNamespace, nameof(rootNamespace));

            _loggerProvider = loggerProvider;
            _projectDir     = projectDir;
            _rootNamespace  = rootNamespace;

            var logger  = new LazyRef <ILogger>(() => loggerProvider.CreateCommandsLogger());
            var startup = new StartupInvoker(logger, startupAssembly, environment, contentRootPath);

            _servicesBuilder = new DesignTimeServicesBuilder(startupAssemblyLoader, startup);
        }
        public MigrationsOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] string assemblyName,
            [NotNull] string startupAssemblyName,
            [NotNull] string projectDir,
            [NotNull] string rootNamespace,
            [CanBeNull] IServiceProvider dnxServices = null)
        {
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotEmpty(assemblyName, nameof(assemblyName));
            Check.NotEmpty(startupAssemblyName, nameof(startupAssemblyName));
            Check.NotNull(projectDir, nameof(projectDir));
            Check.NotNull(rootNamespace, nameof(rootNamespace));

            var loggerFactory = new LoggerFactory();

            loggerFactory.AddProvider(loggerProvider);

            _loggerProvider    = loggerProvider;
            _logger            = new LazyRef <ILogger>(() => loggerFactory.CreateCommandsLogger());
            _projectDir        = projectDir;
            _rootNamespace     = rootNamespace;
            _servicesBuilder   = new DesignTimeServicesBuilder(dnxServices);
            _contextOperations = new DbContextOperations(
                loggerProvider,
                assemblyName,
                startupAssemblyName,
                dnxServices);
        }
        private static void ValidateMigrationAndSnapshotCode(
            DbContext context,
            MigrationCodeGetter migrationCodeGetter,
            SnapshotCodeGetter snapshotCodeGetter)
        {
            const string migrationName = "MyMigration";
            const string rootNamespace = "MyApp.Data";

            var expectedMigration = migrationCodeGetter(migrationName, rootNamespace);
            var expectedSnapshot  = snapshotCodeGetter(rootNamespace);

            var reporter = new OperationReporter(
                new OperationReportHandler(
                    m => Console.WriteLine($"  error: {m}"),
                    m => Console.WriteLine($"   warn: {m}"),
                    m => Console.WriteLine($"   info: {m}"),
                    m => Console.WriteLine($"verbose: {m}")));

            var assembly = System.Reflection.Assembly.GetExecutingAssembly();

            //this works because we have placed the DesignTimeServicesReferenceAttribute
            //in the test project's properties, which simulates
            //the nuget package's build target
            var migration = new DesignTimeServicesBuilder(assembly, assembly, reporter, Array.Empty <string>())
                            .Build(context)
                            .GetRequiredService <IMigrationsScaffolder>()
                            .ScaffoldMigration(migrationName, rootNamespace);

            Assert.Equal(expectedMigration, migration.MigrationCode);
            Assert.Equal(expectedSnapshot, migration.SnapshotCode);
        }
예제 #4
0
        public void ScaffoldModel_works_with_named_connection_string()
        {
            var resolver             = new TestNamedConnectionStringResolver("Data Source=Test");
            var databaseModelFactory = new TestDatabaseModelFactory();
            var scaffolder           = new DesignTimeServicesBuilder(
                typeof(ReverseEngineerScaffolderTest).Assembly,
                typeof(ReverseEngineerScaffolderTest).Assembly,
                new TestOperationReporter(),
                new string[0])
                                       .CreateServiceCollection(SqlServerTestHelpers.Instance.CreateContext())
                                       .AddSingleton <INamedConnectionStringResolver>(resolver)
                                       .AddSingleton <IDatabaseModelFactory>(databaseModelFactory)
                                       .BuildServiceProvider()
                                       .GetRequiredService <IReverseEngineerScaffolder>();

            var result = scaffolder.ScaffoldModel(
                "Name=DefaultConnection",
                new DatabaseModelFactoryOptions(),
                new ModelReverseEngineerOptions(),
                new ModelCodeGenerationOptions {
                ModelNamespace = "Foo"
            });

            Assert.Equal("Data Source=Test", databaseModelFactory.ConnectionString);

            Assert.Contains("Name=DefaultConnection", result.ContextFile.Code);
            Assert.DoesNotContain("Data Source=Test", result.ContextFile.Code);
            Assert.DoesNotContain("#warning", result.ContextFile.Code);
        }
예제 #5
0
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public MigrationsOperations(
        IOperationReporter reporter,
        Assembly assembly,
        Assembly startupAssembly,
        string projectDir,
        string?rootNamespace,
        string?language,
        bool nullable,
        string[]?args)
    {
        _reporter          = reporter;
        _assembly          = assembly;
        _projectDir        = projectDir;
        _rootNamespace     = rootNamespace;
        _language          = language;
        _nullable          = nullable;
        _args              = args ?? Array.Empty <string>();
        _contextOperations = new DbContextOperations(
            reporter,
            assembly,
            startupAssembly,
            projectDir,
            rootNamespace,
            language,
            nullable,
            _args);

        _servicesBuilder = new DesignTimeServicesBuilder(assembly, startupAssembly, reporter, _args);
    }
예제 #6
0
        public MigrationsOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] Assembly assembly,
            [NotNull] Assembly startupAssembly,
            [CanBeNull] string environment,
            [NotNull] string projectDir,
            [NotNull] string rootNamespace)
        {
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotNull(assembly, nameof(assembly));
            Check.NotNull(startupAssembly, nameof(startupAssembly));
            Check.NotNull(projectDir, nameof(projectDir));
            Check.NotNull(rootNamespace, nameof(rootNamespace));

            var loggerFactory = new LoggerFactory();

            loggerFactory.AddProvider(loggerProvider);

            _loggerProvider    = loggerProvider;
            _logger            = new LazyRef <ILogger>(() => loggerFactory.CreateCommandsLogger());
            _assembly          = assembly;
            _projectDir        = projectDir;
            _rootNamespace     = rootNamespace;
            _contextOperations = new DbContextOperations(
                loggerProvider,
                assembly,
                startupAssembly,
                projectDir,
                environment);

            var startup = new StartupInvoker(startupAssembly, environment);

            _servicesBuilder = new DesignTimeServicesBuilder(startup);
        }
        public void ScaffoldModel_works_with_overridden_connection_string()
        {
            var resolver             = new TestNamedConnectionStringResolver("Data Source=Test");
            var databaseModelFactory = new TestDatabaseModelFactory();

            databaseModelFactory.ScaffoldedConnectionString = "Data Source=ScaffoldedConnectionString";
            var scaffolder = new DesignTimeServicesBuilder(
                typeof(ReverseEngineerScaffolderTest).Assembly,
                typeof(ReverseEngineerScaffolderTest).Assembly,
                new TestOperationReporter(),
                new string[0])
                             .CreateServiceCollection("Microsoft.EntityFrameworkCore.SqlServer")
                             .AddSingleton <INamedConnectionStringResolver>(resolver)
                             .AddScoped <IDatabaseModelFactory>(p => databaseModelFactory)
                             .BuildServiceProvider(validateScopes: true)
                             .CreateScope()
                             .ServiceProvider
                             .GetRequiredService <IReverseEngineerScaffolder>();

            var result = scaffolder.ScaffoldModel(
                "Name=DefaultConnection",
                new DatabaseModelFactoryOptions(),
                new ModelReverseEngineerOptions(),
                new ModelCodeGenerationOptions {
                ModelNamespace = "Foo"
            });

            Assert.Contains("Data Source=ScaffoldedConnectionString", result.ContextFile.Code);
            Assert.DoesNotContain("Name=DefaultConnection", result.ContextFile.Code);
            Assert.DoesNotContain("Data Source=Test", result.ContextFile.Code);
        }
예제 #8
0
        public static ScaffoldedModel ScaffoldContext(
            [NotNull] string provider,
            [NotNull] string connectionString,
            [CanBeNull] string outputDir,
            [CanBeNull] string outputContextDir,
            [CanBeNull] string dbContextClassName,
            [NotNull] IEnumerable <string> schemas,
            [NotNull] IEnumerable <string> tables,
            bool useDataAnnotations,
            bool overwriteFiles,
            bool useDatabaseNames)
        {
            var unwrappedReportHandler = ForwardingProxy.Unwrap <IOperationReportHandler>(new OperationReportHandler());
            var reporter         = new OperationReporter(unwrappedReportHandler);
            var _servicesBuilder = new DesignTimeServicesBuilder(Assembly.GetExecutingAssembly(), reporter, Array.Empty <string>());
            var services         = _servicesBuilder.Build(provider);
            var scaffolder       = services.GetRequiredService <IReverseEngineerScaffolder>();
            var @namespace       = "DiplomWork";
            var scaffoldedModel  = scaffolder.ScaffoldModel(
                connectionString,
                tables,
                schemas,
                @namespace,
                null,
                MakeDirRelative(outputDir, outputContextDir),
                dbContextClassName,
                new ModelReverseEngineerOptions {
                UseDatabaseNames = useDatabaseNames
            },
                new ModelCodeGenerationOptions {
                UseDataAnnotations = useDataAnnotations
            });

            return(scaffoldedModel);
        }
예제 #9
0
        public async Task RunAsync(IDbContext context)
        {
            IModel lastModel = null;

            try
            {
                var lastMigration = context.Migrations
                                    .OrderByDescending(e => e.MigrationTime)
                                    .OrderByDescending(e => e.Id) // mysql下自动生成的时间日期字段时间精度为秒
                                    .FirstOrDefault();
                lastModel = lastMigration == null ? null : ((await CreateModelSnapshot(context, Encoding.UTF8.GetString(Convert.FromBase64String(lastMigration.SnapshotDefine))))?.Model);
            }
            catch (DbException) { }

            // 需要从历史版本库中取出快照定义,反序列化成类型 GetDifferences(快照模型, context.Model);
            // 实际情况下要传入历史快照
            var modelDiffer = context.Context
                              .GetInfrastructure()
                              .GetService <IMigrationsModelDiffer>();
            var hasDiffer = modelDiffer.HasDifferences(lastModel, context.Context.Model);

            if (hasDiffer)
            {
                var upOperations = modelDiffer.GetDifferences(lastModel, context.Context.Model);

                using (var trans = context.Context.Database.BeginTransaction())
                {
                    try
                    {
                        context.Context.GetInfrastructure()
                        .GetRequiredService <IMigrationsSqlGenerator>()
                        .Generate(upOperations, context.Context.Model)
                        .ToList()
                        .ForEach(cmd => context.Context.Database.ExecuteSqlCommand(cmd.CommandText));

                        context.Context.Database.CommitTransaction();
                    }
                    catch (DbException ex)
                    {
                        context.Context.Database.RollbackTransaction();
                        throw ex;
                    }

                    string snapshotCode = new DesignTimeServicesBuilder(context.GetType().Assembly, context.GetType().Assembly, new ModuleDbOperationReporter(), new string[0])
                                          .Build((DbContext)context)
                                          .GetService <IMigrationsCodeGenerator>()
                                          .GenerateSnapshot(ContextAssembly, context.GetType(), SnapshotName, context.Context.Model);

                    context.Migrations.Add(new MigrationRecord()
                    {
                        SnapshotDefine = Convert.ToBase64String(Encoding.UTF8.GetBytes(snapshotCode)),
                        MigrationTime  = DateTime.Now
                    });

                    await context.Context.SaveChangesAsync(true);
                }
            }
        }
        /// <summary>
        /// 把model生成快照
        /// </summary>
        /// <param name="_dbContext">efcontent</param>
        /// <param name="nameSpace">快照类的空间名称</param>
        /// <param name="className">快照类的名称</param>
        /// <returns></returns>
        private static string ModelSnapshotToString(EfContent _dbContext, string nameSpace, string className)
        {
            var snapshotCode = new DesignTimeServicesBuilder(typeof(EfContent).Assembly, Assembly.GetEntryAssembly(), new OperationReporter(new OperationReportHandler()), new string[0])
                               .Build((DbContext)_dbContext)
                               .GetService <IMigrationsCodeGenerator>()
                               .GenerateSnapshot(nameSpace, typeof(EfContent), className, _dbContext.Model);//modelSnapshotNamespace:给动态生成类添加nameplace(必须和当前代码所在的命名控件下或者一样)modelSnapshotName:动态生成类的名称

            return(snapshotCode);
        }
        protected static IServiceCollection CreateServices()
        {
            var testAssembly = typeof(ModelCodeGeneratorTestBase).Assembly;
            var reporter     = new TestOperationReporter();
            var services     = new DesignTimeServicesBuilder(testAssembly, testAssembly, reporter, new string[0])
                               .CreateServiceCollection("Microsoft.EntityFrameworkCore.SqlServer");

            return(services);
        }
        public CodeFirstMigrations(string projectPath, Type dbContextType, Func <DbContext> resolveDbContext)
        {
            ProjectPath      = projectPath;
            ResolveDbContext = resolveDbContext;
            var entryAssembly = dbContextType.GetTypeInfo().Assembly;
            var al            = new AssemblyLoader(name => entryAssembly);

            var startupInvoker = new StartupInvoker(entryAssembly, "Debug", projectPath);

            _servicesBuilder = new DesignTimeServicesBuilder(al, startupInvoker);
        }
        public void Design_time_works()
        {
            var services = new DesignTimeServicesBuilder(
                typeof(EndToEndTests).Assembly,
                typeof(EndToEndTests).Assembly,
                new OperationReporter(null),
                Array.Empty <string>())
                           .Build("Microsoft.EntityFrameworkCore.Sqlite");

            var namedConnectionStringResolver = services.GetService <INamedConnectionStringResolver>();

            Assert.IsType <ConfigrationManagerConnectionStringResolver>(namedConnectionStringResolver);
        }
예제 #14
0
        /// <summary>
        /// Automatically migrate the database
        /// Note: The DbContext to be migrated needs to inherit from IKingsDbContext or manually add entity MigrationLog in any way.
        /// </summary>
        /// <param name="dbContext"></param>
        public static void AutoMigratorDatabase(this DbContext dbContext)
        {
            Console.WriteLine($"database begin to magration ......");
            IModel lastModel = null;

            try
            {
                var relationDatabase = dbContext.GetService <IRelationalDatabaseCreator>();
                if (!relationDatabase.Exists())
                {
                    relationDatabase.Create();
                }
                else
                {
                    var lastMigration = dbContext.Set <MigrationLog>()
                                        .OrderByDescending(e => e.Id)
                                        .FirstOrDefault();
                    lastModel = lastMigration == null ? null : (CreateModelSnapshot(lastMigration.SnapshotDefine, typeof(DbContextMigrationExtensions).Namespace
                                                                                    , _dbContentModelSnapshot, dbContext.GetType())?.Model);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            var modelDiffer = dbContext.Database.GetService <IMigrationsModelDiffer>();

            if (modelDiffer.HasDifferences(lastModel, dbContext.Model))
            {
                var upOperations = modelDiffer.GetDifferences(lastModel, dbContext.Model);
                Migrationing(upOperations, dbContext);

                var serviceProvider = new DesignTimeServicesBuilder(dbContext.GetType().Assembly,
                                                                    Assembly.GetEntryAssembly(),
                                                                    new OperationReporter(new OperationReportHandler()), new string[0])
                                      .Build(dbContext);
                var migrationsCodeGenerator = serviceProvider.GetService(typeof(IMigrationsCodeGenerator)) as IMigrationsCodeGenerator;
                var snapshotCode            = migrationsCodeGenerator.GenerateSnapshot(typeof(DbContextMigrationExtensions).Namespace, dbContext.GetType(), _dbContentModelSnapshot, dbContext.Model);
                dbContext.Set <MigrationLog>().Add(new MigrationLog()
                {
                    SnapshotDefine = snapshotCode,
                    MigrationTime  = DateTime.Now
                });
                dbContext.SaveChanges();
            }
            Console.WriteLine($"database magration end......");
        }
            public void ModelChangesAreNotPending()
            {
                var servicesBuilder = new DesignTimeServicesBuilder(Assembly.GetExecutingAssembly(), Mock.Of <IOperationReporter>());
                var services        = servicesBuilder.Build(db);
                var dependencies    = services.GetService <MigrationsScaffolderDependencies>();

                var modelSnapshot = dependencies.MigrationsAssembly.ModelSnapshot;

                Assert.NotNull(modelSnapshot);
                var lastModel    = dependencies.SnapshotModelProcessor.Process(modelSnapshot.Model);
                var upOperations = dependencies.MigrationsModelDiffer.GetDifferences(lastModel, dependencies.Model);

                if (upOperations.Any())
                {
                    throw new XunitException("There are pending model changes.");
                }
            }
예제 #16
0
        private DesignTimeServicesBuilder GetDesignTimeServicesBuilder(string outputPath)
        {
            var assembly = Load(outputPath);

            if (assembly == null)
            {
                throw new ArgumentException("Unable to load project assembly");
            }

            //TODO Use OperationHandler output!!
            var reporter = new OperationReporter(
                new OperationReportHandler());

            var builder = new DesignTimeServicesBuilder(assembly, reporter);

            return(builder);
        }
예제 #17
0
    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
    ///     any release. You should only use it directly in your code with extreme caution and knowing that
    ///     doing so can result in application failures when updating to a new Entity Framework Core release.
    /// </summary>
    public DatabaseOperations(
        IOperationReporter reporter,
        Assembly assembly,
        Assembly startupAssembly,
        string projectDir,
        string?rootNamespace,
        string?language,
        bool nullable,
        string[]?args)
    {
        _projectDir    = projectDir;
        _rootNamespace = rootNamespace;
        _language      = language;
        _nullable      = nullable;
        _args          = args ?? Array.Empty <string>();

        _servicesBuilder = new DesignTimeServicesBuilder(assembly, startupAssembly, reporter, _args);
    }
예제 #18
0
        private void ValidateContextNameInReverseEngineerGenerator(string contextName)
        {
            var assembly        = typeof(ReverseEngineeringConfigurationTests).Assembly;
            var reverseEngineer = new DesignTimeServicesBuilder(assembly, assembly, new TestOperationReporter(), new string[0])
                                  .Build("Microsoft.EntityFrameworkCore.SqlServer")
                                  .GetRequiredService <IReverseEngineerScaffolder>();

            Assert.Equal(
                DesignStrings.ContextClassNotValidCSharpIdentifier(contextName),
                Assert.Throws <ArgumentException>(
                    () => reverseEngineer.ScaffoldModel(
                        "connectionstring",
                        new DatabaseModelFactoryOptions(),
                        new ModelReverseEngineerOptions(),
                        new ModelCodeGenerationOptions {
                ModelNamespace = "FakeNamespace", ContextName = contextName
            }))
                .Message);
        }
예제 #19
0
        public DatabaseOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] string assemblyName,
            [NotNull] string startupAssemblyName,
            [NotNull] string projectDir,
            [NotNull] string rootNamespace,
            [CanBeNull] IServiceProvider dnxServices = null)
        {
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotEmpty(assemblyName, nameof(assemblyName));
            Check.NotEmpty(startupAssemblyName, nameof(startupAssemblyName));
            Check.NotNull(projectDir, nameof(projectDir));
            Check.NotNull(rootNamespace, nameof(rootNamespace));

            _loggerProvider  = loggerProvider;
            _projectDir      = projectDir;
            _rootNamespace   = rootNamespace;
            _servicesBuilder = new DesignTimeServicesBuilder(dnxServices);
        }
예제 #20
0
    private ServiceProvider CreateDesignServiceProvider(
        string assemblyCode,
        string startupAssemblyCode = null,
        DbContext context          = null)
    {
        var assembly        = Compile(assemblyCode);
        var startupAssembly = startupAssemblyCode == null
            ? assembly
            : Compile(startupAssemblyCode);

        var reporter        = new TestOperationReporter();
        var servicesBuilder = new DesignTimeServicesBuilder(assembly, startupAssembly, reporter, new string[0]);

        return((context == null
                ? servicesBuilder
                .CreateServiceCollection("Microsoft.EntityFrameworkCore.SqlServer")
                : servicesBuilder
                .CreateServiceCollection(context))
               .BuildServiceProvider(validateScopes: true));
    }
        public EFCoreAutoMigrator(DbContext _dbContext, ILogger _logger)
        {
            dbMigratorProps = new DBMigratorProps()
            {
                dbContext = _dbContext,
                logger    = _logger,
                dbMigratorTableMetatdata = new DefaultMigrationMetadata(),
                migrationProviderFactory = new MigrationProviderFactory(),
                allowDestructive         = false,
                snapshotHistoryLimit     = -1
            };
            var migrationAssembly             = _dbContext.GetService <IMigrationsAssembly>();
            DesignTimeServicesBuilder builder = new DesignTimeServicesBuilder(migrationAssembly.Assembly, Assembly.GetEntryAssembly(), this, null);
            var dbServices = builder.Build(_dbContext);

            var dependencies  = dbServices.GetRequiredService <MigrationsScaffolderDependencies>();
            var migrationName = dependencies.MigrationsIdGenerator.GenerateId(Utilities.DalConsts.MIGRATION_NAME_PREFIX);

            dbMigratorProps.dbServices    = dbServices;
            dbMigratorProps.migrationName = migrationName;
        }
예제 #22
0
 /// <summary>
 ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
 ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
 ///     any release. You should only use it directly in your code with extreme caution and knowing that
 ///     doing so can result in application failures when updating to a new Entity Framework Core release.
 /// </summary>
 protected DbContextOperations(
     IOperationReporter reporter,
     Assembly assembly,
     Assembly startupAssembly,
     string projectDir,
     string?rootNamespace,
     string?language,
     bool nullable,
     string[]?args,
     AppServiceProviderFactory appServicesFactory)
 {
     _reporter           = reporter;
     _assembly           = assembly;
     _startupAssembly    = startupAssembly;
     _projectDir         = projectDir;
     _rootNamespace      = rootNamespace;
     _language           = language;
     _nullable           = nullable;
     _args               = args ?? Array.Empty <string>();
     _appServicesFactory = appServicesFactory;
     _servicesBuilder    = new DesignTimeServicesBuilder(assembly, startupAssembly, reporter, _args);
 }
예제 #23
0
        public DatabaseOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] string assemblyName,
            [NotNull] string startupAssemblyName,
            [CanBeNull] string environment,
            [NotNull] string projectDir,
            [NotNull] string rootNamespace)
        {
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotEmpty(assemblyName, nameof(assemblyName));
            Check.NotEmpty(startupAssemblyName, nameof(startupAssemblyName));
            Check.NotNull(projectDir, nameof(projectDir));
            Check.NotNull(rootNamespace, nameof(rootNamespace));

            _loggerProvider = loggerProvider;
            _projectDir     = projectDir;
            _rootNamespace  = rootNamespace;

            var startup = new StartupInvoker(startupAssemblyName, environment);

            _servicesBuilder = new DesignTimeServicesBuilder(startup);
        }
        public DbContextOperations(
            [NotNull] ILoggerProvider loggerProvider,
            [NotNull] Assembly assembly,
            [NotNull] Assembly startupAssembly,
            [NotNull] string projectDir,
            [CanBeNull] string environment)
        {
            Check.NotNull(loggerProvider, nameof(loggerProvider));
            Check.NotNull(assembly, nameof(assembly));
            Check.NotNull(startupAssembly, nameof(startupAssembly));
            Check.NotEmpty(projectDir, nameof(projectDir));

            _loggerProvider  = loggerProvider;
            _assembly        = assembly;
            _startupAssembly = startupAssembly;
            _projectDir      = projectDir;
            _logger          = new LazyRef <ILogger>(() => _loggerProvider.CreateCommandsLogger());

            var startup = new StartupInvoker(startupAssembly, environment);

            _runtimeServices = startup.ConfigureServices();

            _servicesBuilder = new DesignTimeServicesBuilder(startup);
        }
예제 #25
0
        public async Task RunAsync(IDbContext context)
        {
            IModel lastModel = null;
            var    contextServiceProvider = context.Context.GetInfrastructure();

            var store = context.Context.GetService <IStore>();

            await new InitlizationDbContext(store.CreateOptions(false)).Database.EnsureCreatedAsync();

            try
            {
                var lastMigration = context.Migrations
                                    .OrderByDescending(e => e.MigrationTime)
                                    .OrderByDescending(e => e.Id) // mysql下自动生成的时间日期字段时间精度为秒
                                    .FirstOrDefault();
                lastModel = lastMigration == null ? null : ((await CreateModelSnapshot(context, Encoding.UTF8.GetString(Convert.FromBase64String(lastMigration.SnapshotDefine))))?.Model);
            }
            catch (DbException) { }

            var designTimeServices = new DesignTimeServicesBuilder(
                context.Context.GetType().Assembly,
                context.Context.GetType().Assembly,
                new OperationReporter(),
                new string[0]).Build(context.Context);
            var process = designTimeServices.GetService <ISnapshotModelProcessor>();

            // 需要从历史版本库中取出快照定义,反序列化成类型 GetDifferences(快照模型, context.Model);
            // 实际情况下要传入历史快照
            var modelDiffer = contextServiceProvider.GetService <IMigrationsModelDiffer>();
            var hasDiffer   = modelDiffer.HasDifferences(
                lastModel != null ? process.Process(lastModel).GetRelationalModel() : null,
                context.Context.Model.GetRelationalModel());

            if (!hasDiffer)
            {
                return;
            }

            var upOperations = modelDiffer.GetDifferences(
                lastModel != null ? lastModel.GetRelationalModel() : null,
                context.Context.Model.GetRelationalModel());

            using (var trans = context.Context.Database.BeginTransaction())
            {
                try
                {
                    contextServiceProvider.GetRequiredService <IMigrationsSqlGenerator>()
                    .Generate(upOperations, context.Context.Model)
                    .ToList()
                    .ForEach(cmd => context.Context.Database.ExecuteSqlRaw(cmd.CommandText));

                    trans.Commit();
                }
                catch (DbException ex)
                {
                    trans.Rollback();
                    throw ex;
                }

                context.Migrations.Add(new MigrationRecord()
                {
                    SnapshotDefine = await CreateSnapshotCode(designTimeServices, context),
                    MigrationTime  = DateTime.Now
                });

                await context.Context.SaveChangesAsync(true);
            }
        }