Exemplo n.º 1
0
        public virtual Task<IReadOnlyList<string>> ReverseEngineerAsync(
            [NotNull] string runtimeProviderAssemblyName,
            [NotNull] string connectionString,
            [NotNull] string rootNamespace,
            [NotNull] string projectDir,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Check.NotEmpty(runtimeProviderAssemblyName, nameof(runtimeProviderAssemblyName));
            Check.NotEmpty(connectionString, nameof(connectionString));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));
            Check.NotEmpty(projectDir, nameof(projectDir));

            var designTimeMetadataProviderFactory =
                GetDesignTimeMetadataProviderFactory(runtimeProviderAssemblyName);
            var serviceCollection = SetupInitialServices();
            designTimeMetadataProviderFactory.AddMetadataProviderServices(serviceCollection);

            var serviceProvider = serviceCollection.BuildServiceProvider();
            var designTimeProvider = serviceProvider.GetRequiredService<IDatabaseMetadataModelProvider>();
            var generator = serviceProvider.GetRequiredService<ReverseEngineeringGenerator>();
            var configuration = new ReverseEngineeringConfiguration
            {
                Provider = designTimeProvider,
                ConnectionString = connectionString,
                Namespace = rootNamespace,
                CustomTemplatePath = projectDir,
                OutputPath = projectDir
            };

            return generator.GenerateAsync(configuration, cancellationToken);
        }
Exemplo n.º 2
0
        public virtual IEnumerable<string> ReverseEngineer(
            [NotNull] string providerAssemblyName,
            [NotNull] string connectionString,
            [NotNull] string rootNamespace,
            [NotNull] string projectDir)
        {
            Check.NotNull(providerAssemblyName, nameof(providerAssemblyName));
            Check.NotEmpty(connectionString, nameof(connectionString));
            Check.NotEmpty(rootNamespace, nameof(rootNamespace));
            Check.NotEmpty(projectDir, nameof(projectDir));

            var assembly = Assembly.Load(new AssemblyName(providerAssemblyName));
            if (assembly == null)
            {
                throw new InvalidOperationException(Strings.CannotFindAssembly(providerAssemblyName));
            }

            var configuration = new ReverseEngineeringConfiguration()
            {
                ProviderAssembly = assembly,
                ConnectionString = connectionString,
                Namespace = rootNamespace,
                OutputPath = projectDir
            };

            var generator = new ReverseEngineeringGenerator(_serviceProvider);
            return generator.GenerateAsync(configuration).Result;
        }
Exemplo n.º 3
0
        public void Throws_exceptions_for_incorrect_configuration()
        {
            var configuration = new ReverseEngineeringConfiguration
            {
                ConnectionString = null,
                ProjectPath      = null,
                OutputPath       = null
            };

            Assert.Equal(RelationalDesignStrings.ConnectionStringRequired,
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ConnectionString = "NonEmptyConnectionString";
            Assert.Equal(RelationalDesignStrings.ProjectPathRequired,
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ProjectPath = "NonEmptyProjectPath";
            Assert.Equal(RelationalDesignStrings.RootNamespaceRequired,
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ContextClassName = @"Invalid!CSharp*Class&Name";
            Assert.Equal(RelationalDesignStrings.ContextClassNotValidCSharpIdentifier(@"Invalid!CSharp*Class&Name"),
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ContextClassName = "1CSharpClassNameCannotStartWithNumber";
            Assert.Equal(RelationalDesignStrings.ContextClassNotValidCSharpIdentifier("1CSharpClassNameCannotStartWithNumber"),
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ContextClassName = "volatile";  // cannot be C# keyword
            Assert.Equal(RelationalDesignStrings.ContextClassNotValidCSharpIdentifier("volatile"),
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.ContextClassName = "GoodClassName";
            configuration.OutputPath       = @"\AnAbsolutePath";
            Assert.Equal(RelationalDesignStrings.RootNamespaceRequired,
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);

            configuration.OutputPath = @"A\Relative\Path";
            Assert.Equal(RelationalDesignStrings.RootNamespaceRequired,
                         Assert.Throws <ArgumentException>(
                             () => configuration.CheckValidity()).Message);
        }
Exemplo n.º 4
0
        public virtual IModel GetMetadataModel([NotNull] ReverseEngineeringConfiguration configuration)
        {
            Check.NotNull(configuration, nameof(configuration));

            var metadataModel = _provider.GenerateMetadataModel(
                configuration.ConnectionString, configuration.TableSelectionSet);

            if (metadataModel == null)
            {
                throw new InvalidOperationException(
                          RelationalDesignStrings.ProviderReturnedNullModel(
                              _provider.GetType().FullName,
                              configuration.ConnectionString));
            }

            return(metadataModel);
        }
        public virtual IModel GetMetadataModel(
            [NotNull] IDatabaseMetadataModelProvider provider,
            [NotNull] ReverseEngineeringConfiguration configuration)
        {
            Check.NotNull(provider, nameof(provider));
            Check.NotNull(configuration, nameof(configuration));

            var metadataModel = provider
                                .GenerateMetadataModel(configuration.ConnectionString);

            if (metadataModel == null)
            {
                throw new InvalidOperationException(
                          Strings.ProviderReturnedNullModel(
                              provider.GetType().FullName,
                              configuration.ConnectionString));
            }

            return(metadataModel);
        }
Exemplo n.º 6
0
        public virtual Task <ReverseEngineerFiles> GenerateAsync(
            [NotNull] ReverseEngineeringConfiguration configuration,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Check.NotNull(configuration, nameof(configuration));

            cancellationToken.ThrowIfCancellationRequested();

            configuration.CheckValidity();

            var metadataModel = GetMetadataModel(configuration);
            var @namespace    = ConstructNamespace(configuration.ProjectRootNamespace,
                                                   configuration.ProjectPath, configuration.OutputPath);

            var customConfiguration = new CustomConfiguration()
            {
                ConnectionString = configuration.ConnectionString,
                ContextClassName = configuration.ContextClassName,
                Namespace        = @namespace,
                UseFluentApiOnly = configuration.UseFluentApiOnly,
            };
            var modelConfiguration = _modelConfigurationFactory
                                     .CreateModelConfiguration(metadataModel, customConfiguration);

            var dbContextClassName =
                string.IsNullOrWhiteSpace(customConfiguration.ContextClassName)
                ? modelConfiguration.ClassName()
                : customConfiguration.ContextClassName;

            CheckOutputFiles(configuration.ProjectPath,
                             configuration.OutputPath, dbContextClassName, metadataModel);

            var outputPath = configuration.OutputPath == null
                ? configuration.ProjectPath
                : (Path.IsPathRooted(configuration.OutputPath)
                    ? configuration.OutputPath
                    : Path.Combine(configuration.ProjectPath, configuration.OutputPath));

            return(CodeWriter.WriteCodeAsync(
                       modelConfiguration, outputPath, dbContextClassName, cancellationToken));
        }
        private static void CheckConfiguration(ReverseEngineeringConfiguration configuration)
        {
            if (configuration.ProviderAssembly == null)
            {
                throw new ArgumentException(Strings.ProviderAssemblyRequired);
            }

            if (string.IsNullOrEmpty(configuration.ConnectionString))
            {
                throw new ArgumentException(Strings.ConnectionStringRequired);
            }

            if (string.IsNullOrEmpty(configuration.OutputPath))
            {
                throw new ArgumentException(Strings.OutputPathRequired);
            }

            if (string.IsNullOrEmpty(configuration.Namespace))
            {
                throw new ArgumentException(Strings.NamespaceRequired);
            }
        }
        public virtual async Task <List <string> > GenerateAsync(
            [NotNull] ReverseEngineeringConfiguration configuration,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Check.NotNull(configuration, nameof(configuration));

            CheckConfiguration(configuration);

            var resultingFiles   = new List <string>();
            var providerAssembly = configuration.ProviderAssembly;
            var provider         = GetProvider(providerAssembly);
            var metadataModel    = GetMetadataModel(provider, configuration);

            var dbContextGeneratorModel = new DbContextGeneratorModel
            {
                ClassName        = configuration.ContextClassName,
                Namespace        = configuration.Namespace,
                ProviderAssembly = configuration.ProviderAssembly.FullName,
                ConnectionString = configuration.ConnectionString,
                Generator        = this,
                MetadataModel    = metadataModel
            };
            var dbContextCodeGeneratorHelper = provider.DbContextCodeGeneratorHelper(dbContextGeneratorModel);

            dbContextGeneratorModel.Helper = dbContextCodeGeneratorHelper;

            var dbContextClassName = configuration.ContextClassName
                                     ?? dbContextCodeGeneratorHelper.ClassName(configuration.ConnectionString);

            CheckOutputFiles(configuration.OutputPath, dbContextClassName, metadataModel);

            var templating        = _serviceProvider.GetRequiredService <ITemplating>();
            var dbContextTemplate = provider.DbContextTemplate;
            var templateResult    = await templating.RunTemplateAsync(dbContextTemplate, dbContextGeneratorModel, provider);

            if (templateResult.ProcessingException != null)
            {
                throw new InvalidOperationException(
                          Strings.ErrorRunningDbContextTemplate(templateResult.ProcessingException.Message));
            }

            // output DbContext .cs file
            var dbContextFileName     = dbContextClassName + FileExtension;
            var dbContextFileFullPath = FileService.OutputFile(
                configuration.OutputPath, dbContextFileName, templateResult.GeneratedText);

            resultingFiles.Add(dbContextFileFullPath);

            var entityTypeTemplate = provider.EntityTypeTemplate;

            foreach (var entityType in metadataModel.EntityTypes)
            {
                var entityTypeGeneratorModel = new EntityTypeGeneratorModel()
                {
                    EntityType       = entityType,
                    Namespace        = configuration.Namespace,
                    ProviderAssembly = configuration.ProviderAssembly.FullName,
                    ConnectionString = configuration.ConnectionString,
                    Generator        = this
                };
                var entityTypeCodeGeneratorHelper = provider.EntityTypeCodeGeneratorHelper(entityTypeGeneratorModel);
                entityTypeGeneratorModel.Helper = entityTypeCodeGeneratorHelper;

                templateResult = await templating.RunTemplateAsync(entityTypeTemplate, entityTypeGeneratorModel, provider);

                if (templateResult.ProcessingException != null)
                {
                    throw new InvalidOperationException(
                              Strings.ErrorRunningEntityTypeTemplate(templateResult.ProcessingException.Message));
                }

                // output EntityType poco .cs file
                var entityTypeFileName     = entityType.DisplayName() + FileExtension;
                var entityTypeFileFullPath = FileService.OutputFile(
                    configuration.OutputPath, entityTypeFileName, templateResult.GeneratedText);
                resultingFiles.Add(entityTypeFileFullPath);
            }

            return(resultingFiles);
        }
        private static void CheckConfiguration(ReverseEngineeringConfiguration configuration)
        {
            if (configuration.ProviderAssembly == null)
            {
                throw new ArgumentException(Strings.ProviderAssemblyRequired);
            }

            if (string.IsNullOrEmpty(configuration.ConnectionString))
            {
                throw new ArgumentException(Strings.ConnectionStringRequired);
            }

            if (string.IsNullOrEmpty(configuration.OutputPath))
            {
                throw new ArgumentException(Strings.OutputPathRequired);
            }

            if (string.IsNullOrEmpty(configuration.Namespace))
            {
                throw new ArgumentException(Strings.NamespaceRequired);
            }
        }
        public virtual async Task <List <string> > GenerateAsync(
            [NotNull] ReverseEngineeringConfiguration configuration,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            Check.NotNull(configuration, nameof(configuration));

            CheckConfiguration(configuration);

            var resultingFiles   = new List <string>();
            var providerAssembly = configuration.ProviderAssembly;
            var provider         = GetProvider(providerAssembly);
            var metadataModel    = GetMetadataModel(provider, configuration);

            var dbContextGeneratorModel = new DbContextGeneratorModel
            {
                ClassName        = configuration.ContextClassName,
                Namespace        = configuration.Namespace,
                ProviderAssembly = configuration.ProviderAssembly.FullName,
                ConnectionString = configuration.ConnectionString,
                MetadataModel    = metadataModel
            };

            //TODO - check to see whether user has an override class for this in the current project first
            var dbContextCodeGenerator =
                provider.GetContextModelCodeGenerator(this, dbContextGeneratorModel);

            if (dbContextCodeGenerator == null)
            {
                throw new InvalidOperationException(
                          Strings.NoContextModelCodeGenerator(provider.GetType().FullName));
            }

            CheckOutputFiles(configuration.OutputPath, dbContextCodeGenerator.ClassName, metadataModel);

            var contextStringBuilder = new IndentedStringBuilder();

            dbContextCodeGenerator.Generate(contextStringBuilder);

            // output DbContext .cs file
            var dbContextFileName = dbContextCodeGenerator.ClassName + FileExtension;

            using (var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(contextStringBuilder.ToString())))
            {
                await OutputFile(configuration.OutputPath, dbContextFileName, sourceStream);
            }
            resultingFiles.Add(Path.Combine(configuration.OutputPath, dbContextFileName));

            foreach (var entityType in metadataModel.EntityTypes)
            {
                var entityTypeGeneratorModel = new EntityTypeGeneratorModel()
                {
                    EntityType       = entityType,
                    Namespace        = configuration.Namespace,
                    ProviderAssembly = configuration.ProviderAssembly.FullName,
                    ConnectionString = configuration.ConnectionString,
                };

                //TODO - check to see whether user has an override class for this in the current project first
                var entityTypeCodeGenerator =
                    provider.GetEntityTypeModelCodeGenerator(
                        this,
                        entityTypeGeneratorModel);
                if (entityTypeCodeGenerator == null)
                {
                    throw new InvalidOperationException(
                              Strings.NoEntityTypeModelCodeGenerator(provider.GetType().FullName));
                }

                var entityTypeStringBuilder = new IndentedStringBuilder();
                entityTypeCodeGenerator.Generate(entityTypeStringBuilder);

                // output EntityType poco .cs file
                using (var sourceStream = new MemoryStream(Encoding.UTF8.GetBytes(entityTypeStringBuilder.ToString())))
                {
                    var entityTypeFileName = entityType.Name + FileExtension;
                    await OutputFile(configuration.OutputPath, entityTypeFileName, sourceStream);

                    resultingFiles.Add(Path.Combine(configuration.OutputPath, entityTypeFileName));
                }
            }

            return(resultingFiles);
        }
Exemplo n.º 11
0
        public async void It_uses_templates()
        {
            var dbContextFileName = "EntityFramework.Sqlite.Design." + ReverseEngineeringGenerator.DbContextTemplateFileName;
            var entityTypeFileName = "EntityFramework.Sqlite.Design." + ReverseEngineeringGenerator.EntityTypeTemplateFileName;
            var entityTemplate = "This is an entity type template! (For real)";
            var contextTemplate = "Also a 100% legit template";
            var outputDir = "gen";
            var templatesDir = "templates";

            using (var testStore = SqliteTestStore.CreateScratch())
            {
                testStore.ExecuteNonQuery("CREATE TABLE RealMccoy ( Col1 text PRIMARY KEY); ");

                InMemoryFiles.OutputFile(templatesDir, dbContextFileName, contextTemplate);
                InMemoryFiles.OutputFile(templatesDir, entityTypeFileName, entityTemplate);

                var config = new ReverseEngineeringConfiguration
                    {
                        ConnectionString = testStore.Connection.ConnectionString,
                        Provider = MetadataModelProvider,
                        Namespace = "Test",
                        OutputPath = outputDir,
                        CustomTemplatePath = templatesDir
                    };
                var filePaths = await Generator.GenerateAsync(config);

                var expectedLog = new LoggerMessages
                    {
                        Info =
                            {
                                "Using custom template " + Path.Combine(templatesDir, dbContextFileName),
                                "Using custom template " + Path.Combine(templatesDir, entityTypeFileName)
                            }
                    };
                AssertLog(expectedLog);

                Assert.Equal(2, filePaths.Count);

                foreach (var fileName in filePaths.Select(Path.GetFileName))
                {
                    var fileContents = InMemoryFiles.RetrieveFileContents(outputDir, fileName);
                    var contents = fileName.EndsWith("Context.cs") ? contextTemplate : entityTemplate;
                    Assert.Equal(contents, fileContents);
                }
            }
        }