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