public static ReverseEngineerOptions TryRead(string optionsPath) { if (!File.Exists(optionsPath)) { return(null); } if (File.Exists(optionsPath + ".ignore")) { return(null); } // Top-down deserialization: // Try to deserialize the current head version of the class. // If this fails, go top down with older versions and migrate them to the head version. var couldRead = TryRead(optionsPath, out ReverseEngineerOptions deserialized); if (couldRead) { return(deserialized); } couldRead = TryRead(optionsPath, out ReverseEngineerOptionsV1 deserializedV1); if (couldRead) { return(ReverseEngineerOptions.FromV1(deserializedV1)); } // Fallback return(null); }
public ReverseEngineerOptions TryReadOptions(string optionsPath) { if (!File.Exists(optionsPath)) { return(null); } if (File.Exists(optionsPath + ".ignore")) { return(null); } ReverseEngineerOptions deserializedOptions = null; try { var ms = new MemoryStream(Encoding.UTF8.GetBytes(File.ReadAllText(optionsPath, Encoding.UTF8))); var ser = new DataContractJsonSerializer(typeof(ReverseEngineerOptions)); deserializedOptions = ser.ReadObject(ms) as ReverseEngineerOptions; ms.Close(); } catch (Exception ex) { _package.LogError(new List <string> { "Unable to load options" }, ex); } return(deserializedOptions); }
private IReverseEngineerScaffolder CreateScaffolder(ReverseEngineerOptions options) { var fileService = new InMemoryTemplateFileService(); fileService.InputFiles(ContextClassTemplate, ContextImportsTemplate, ContextCtorTemplate, ContextOnConfiguringTemplate, ContextDbSetsTemplate, EntityClassTemplate, EntityImportsTemplate, EntityCtorTemplate, EntityPropertiesTemplate); var services = new ServiceCollection() .AddEntityFrameworkDesignTimeServices() .AddSingleton <IDbContextTemplateService, FakeHbsDbContextTemplateService>() .AddSingleton <IEntityTypeTemplateService, FakeHbsEntityTypeTemplateService>() .AddSingleton <IEntityTypeTransformationService, HbsEntityTypeTransformationService>() .AddSingleton <ITypeScriptHelper, TypeScriptHelper>() .AddSingleton <ITemplateFileService>(fileService) .AddSingleton <ITemplateLanguageService, FakeTypeScriptTemplateLanguageService>() .AddSingleton <IModelCodeGenerator, HbsTypeScriptModelGenerator>() .AddSingleton(provider => { ICSharpDbContextGenerator contextGenerator = new HbsCSharpDbContextGenerator( provider.GetRequiredService <IProviderConfigurationCodeGenerator>(), provider.GetRequiredService <IAnnotationCodeGenerator>(), provider.GetRequiredService <IDbContextTemplateService>(), provider.GetRequiredService <IEntityTypeTransformationService>(), provider.GetRequiredService <ICSharpHelper>(), provider.GetRequiredService <IOptions <HandlebarsScaffoldingOptions> >()); return(options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextAndEntities ? contextGenerator : new NullCSharpDbContextGenerator()); }) .AddSingleton(provider => { ICSharpEntityTypeGenerator entityGenerator = new HbsTypeScriptEntityTypeGenerator( provider.GetRequiredService <IEntityTypeTemplateService>(), provider.GetRequiredService <IEntityTypeTransformationService>(), provider.GetRequiredService <ICSharpHelper>(), provider.GetRequiredService <ITypeScriptHelper>(), provider.GetRequiredService <IOptions <HandlebarsScaffoldingOptions> >()); return(options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities ? entityGenerator : new NullCSharpEntityTypeGenerator()); }) .AddSingleton <IHbsHelperService>(provider => new HbsHelperService(new Dictionary <string, Action <TextWriter, Dictionary <string, object>, object[]> > { { EntityFrameworkCore.Scaffolding.Handlebars.Helpers.Constants.SpacesHelper, HandlebarsHelpers.SpacesHelper } })) .AddSingleton <IHbsBlockHelperService>(provider => new HbsBlockHelperService(new Dictionary <string, Action <TextWriter, HelperOptions, Dictionary <string, object>, object[]> >())) .AddSingleton <IReverseEngineerScaffolder, HbsReverseEngineerScaffolder>(); new SqlServerDesignTimeServices().ConfigureDesignTimeServices(services); var scaffolder = services .BuildServiceProvider() .GetRequiredService <IReverseEngineerScaffolder>(); return(scaffolder); }
public static ReverseEngineerResult LaunchExternalRunner(ReverseEngineerOptions options, bool useEFCore5) { var commandOptions = new ReverseEngineerCommandOptions { ConnectionString = options.ConnectionString, ContextClassName = options.ContextClassName, CustomReplacers = options.CustomReplacers, Dacpac = options.Dacpac, DatabaseType = options.DatabaseType, DefaultDacpacSchema = options.DefaultDacpacSchema, IncludeConnectionString = options.IncludeConnectionString, OutputPath = options.OutputPath, ContextNamespace = options.ContextNamespace, ModelNamespace = options.ModelNamespace, OutputContextPath = options.OutputContextPath, ProjectPath = options.ProjectPath, ProjectRootNamespace = options.ProjectRootNamespace, SelectedHandlebarsLanguage = options.SelectedHandlebarsLanguage, SelectedToBeGenerated = options.SelectedToBeGenerated, Tables = options.Tables, UseDatabaseNames = options.UseDatabaseNames, UseFluentApiOnly = options.UseFluentApiOnly, UseHandleBars = options.UseHandleBars, UseInflector = options.UseInflector, UseLegacyPluralizer = options.UseLegacyPluralizer, UseSpatial = options.UseSpatial, UseDbContextSplitting = options.UseDbContextSplitting, UseNodaTime = options.UseNodaTime, UseBoolPropertiesWithoutDefaultSql = options.UseBoolPropertiesWithoutDefaultSql, }; var launcher = new EfRevEngLauncher(commandOptions, useEFCore5); return(launcher.GetOutput()); }
private void SaveOptions(Project project, string optionsPath, ReverseEngineerOptions options) { if (!File.Exists(optionsPath + ".ignore")) { File.WriteAllText(optionsPath, options.Write(), Encoding.UTF8); project.ProjectItems.AddFromFile(optionsPath); } }
public string WriteOptions(ReverseEngineerOptions options) { var ms = new MemoryStream(); var ser = new DataContractJsonSerializer(typeof(ReverseEngineerOptions)); ser.WriteObject(ms, options); byte[] json = ms.ToArray(); ms.Close(); return(Encoding.UTF8.GetString(json, 0, json.Length)); }
/// <summary> /// <para> /// Registers the Handlebars scaffolding generator as a service in the <see cref="IServiceCollection" />. /// This allows you to customize generated DbContext and entity type classes by modifying the Handlebars /// templates in the CodeTemplates folder. /// </para> /// <para> /// Has <paramref name="options" /> that allow you to choose whether to generate only the DbContext class, /// only entity type classes, or both DbContext and entity type classes (the default). /// </para> /// </summary> /// <param name="services"> The <see cref="IServiceCollection" /> to add services to. </param> /// <param name="options">Options for reverse engineering classes from an existing database.</param> /// <param name="language">Language option.</param> /// <returns>The same service collection so that multiple calls can be chained.</returns> public static IServiceCollection AddHandlebarsScaffolding(this IServiceCollection services, ReverseEngineerOptions options = ReverseEngineerOptions.DbContextAndEntities, LanguageOptions language = LanguageOptions.CSharp) { return(services.AddHandlebarsScaffolding(scaffoldingOptions => { scaffoldingOptions.ReverseEngineerOptions = options; scaffoldingOptions.LanguageOptions = language; })); }
private void SaveOptions(Project project, string optionsPath, ReverseEngineerOptions options, Tuple <List <Schema>, string> renamingOptions) { if (!File.Exists(optionsPath + ".ignore")) { File.WriteAllText(optionsPath, options.Write(), Encoding.UTF8); project.ProjectItems.AddFromFile(optionsPath); } if (renamingOptions.Item1 != null && !File.Exists(renamingOptions.Item2 + ".ignore")) { File.WriteAllText(renamingOptions.Item2, CustomNameOptionsExtensions.Write(renamingOptions.Item1), Encoding.UTF8); project.ProjectItems.AddFromFile(renamingOptions.Item2); } }
public static string Write(this ReverseEngineerOptions options) { using (var ms = new MemoryStream()) { using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8, true, true, " ")) { var serializer = new DataContractJsonSerializer(typeof(ReverseEngineerOptions)); serializer.WriteObject(writer, options); writer.Flush(); } var json = ms.ToArray(); return(Encoding.UTF8.GetString(json, 0, json.Length)); } }
/// <summary> /// <para> /// Registers the Handlebars scaffolding generator as a service in the <see cref="IServiceCollection" />. /// This allows you to customize generated DbContext and entity type classes by modifying the Handlebars /// templates in the CodeTemplates folder. /// </para> /// <para> /// Has <paramref name="options" /> that allow you to choose whether to generate only the DbContext class, /// only entity type classes, or both DbContext and entity type classes (the default). /// This can be useful when placing model classes in a separate class library. /// </para> /// </summary> /// <param name="services"> The <see cref="IServiceCollection" /> to add services to. </param> /// <param name="options">Options for reverse engineering classes from an existing database.</param> /// <returns>The same service collection so that multiple calls can be chained.</returns> public static IServiceCollection AddHandlebarsScaffolding(this IServiceCollection services, ReverseEngineerOptions options = ReverseEngineerOptions.DbContextAndEntities) { Type dbContextGeneratorImpl; var dbContextGeneratorType = typeof(ICSharpDbContextGenerator); if (options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextAndEntities) { dbContextGeneratorImpl = typeof(HbsCSharpDbContextGenerator); } else { dbContextGeneratorImpl = typeof(NullCSharpDbContextGenerator); } services.AddSingleton(dbContextGeneratorType, dbContextGeneratorImpl); Type entityGeneratorImpl; var entityGeneratorType = typeof(ICSharpEntityTypeGenerator); if (options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities) { entityGeneratorImpl = typeof(HbsCSharpEntityTypeGenerator); } else { entityGeneratorImpl = typeof(NullCSharpEntityTypeGenerator); } services.AddSingleton(entityGeneratorType, entityGeneratorImpl); services.AddSingleton <ITemplateFileService, FileSystemTemplateFileService>(); services.AddSingleton <IDbContextTemplateService, HbsDbContextTemplateService>(); services.AddSingleton <IEntityTypeTemplateService, HbsEntityTypeTemplateService>(); services.AddSingleton <IModelCodeGenerator, HbsCSharpModelGenerator>(); services.AddSingleton <IReverseEngineerScaffolder, HbsReverseEngineerScaffolder>(); services.AddSingleton <IEntityTypeTransformationService, HbsEntityTypeTransformationService>(); services.AddSingleton <IHbsHelperService, HbsHelperService>(provider => { var helpers = new Dictionary <string, Action <TextWriter, Dictionary <string, object>, object[]> > { { Constants.SpacesHelper, HandlebarsHelpers.SpacesHelper } }; return(new HbsHelperService(helpers)); }); return(services); }
private Dictionary <string, string> GetGeneratedFiles(ScaffoldedModel model, ReverseEngineerOptions options) { var generatedFiles = new Dictionary <string, string>(); if (options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextAndEntities) { generatedFiles.Add(Constants.Files.TypeScriptFiles.DbContextFile, model.ContextFile.Code); } if (options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities) { generatedFiles.Add(Constants.Files.TypeScriptFiles.CategoryFile, model.AdditionalFiles[0].Code); generatedFiles.Add(Constants.Files.TypeScriptFiles.ProductFile, model.AdditionalFiles[1].Code); } return(generatedFiles); }
public static string Write(this ReverseEngineerOptions options, string projectDirectory) { if (!string.IsNullOrEmpty(options.UiHint)) { options.UiHint = SetRelativePathForSqlProj(options.UiHint, projectDirectory); } using (var ms = new MemoryStream()) { using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.UTF8, true, true, " ")) { var serializer = new DataContractJsonSerializer(typeof(ReverseEngineerOptions)); serializer.WriteObject(writer, options); writer.Flush(); } var json = ms.ToArray(); return(Encoding.UTF8.GetString(json, 0, json.Length)); } }
public EfCoreModelDialog(ReverseEngineerOptions options) { _options = options; Telemetry.TrackPageView(nameof(EfCoreModelDialog)); InitializeComponent(); Background = VsThemes.GetWindowBackground(); if (_options != null) { chkDataAnnoations.IsChecked = !options.UseFluentApiOnly; chkUseDatabaseNames.IsChecked = options.UseDatabaseNames; chkPluralize.IsChecked = options.UseInflector; chkHandlebars.IsChecked = options.UseHandleBars; chkIdReplace.IsChecked = options.IdReplace; chkIncludeConnectionString.IsChecked = options.IncludeConnectionString; ModelName = options.ContextClassName; NameSpace = options.ProjectRootNamespace; OutputPath = options.OutputPath; cmbLanguage.SelectedIndex = options.SelectedToBeGenerated; SetCheckState(); } }
public static ReverseEngineerOptions TryRead(string optionsPath) { if (!File.Exists(optionsPath)) { return(null); } if (File.Exists(optionsPath + ".ignore")) { return(null); } ReverseEngineerOptions deserializedOptions = null; try { var ms = new MemoryStream(Encoding.UTF8.GetBytes(File.ReadAllText(optionsPath, Encoding.UTF8))); var ser = new DataContractJsonSerializer(typeof(ReverseEngineerOptions)); deserializedOptions = ser.ReadObject(ms) as ReverseEngineerOptions; ms.Close(); } catch { } return(deserializedOptions); }
/// <summary> /// <para> /// Registers the Handlebars scaffolding generator as a service in the <see cref="IServiceCollection" />. /// This allows you to customize generated DbContext and entity type classes by modifying the Handlebars /// templates in the CodeTemplates folder. /// </para> /// <para> /// Has <paramref name="options" /> that allow you to choose whether to generate only the DbContext class, /// only entity type classes, or both DbContext and entity type classes (the default). /// This can be useful when placing model classes in a separate class library. /// </para> /// </summary> /// <param name="services"> The <see cref="IServiceCollection" /> to add services to. </param> /// <param name="options">Options for reverse engineering classes from an existing database.</param> /// <returns>The same service collection so that multiple calls can be chained.</returns> public static IServiceCollection AddHandlebarsScaffolding(this IServiceCollection services, ReverseEngineerOptions options = ReverseEngineerOptions.DbContextAndEntities) { Type dbContextGeneratorImpl; var dbContextGeneratorType = typeof(ICSharpDbContextGenerator); if (options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextAndEntities) { dbContextGeneratorImpl = typeof(HbsCSharpDbContextGenerator); } else { dbContextGeneratorImpl = typeof(NullCSharpDbContextGenerator); } services.AddSingleton(dbContextGeneratorType, dbContextGeneratorImpl); Type entityGeneratorImpl; var entityGeneratorType = typeof(ICSharpEntityTypeGenerator); if (options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities) { entityGeneratorImpl = typeof(HbsCSharpEntityTypeGenerator); } else { entityGeneratorImpl = typeof(NullCSharpEntityTypeGenerator); } services.AddSingleton(entityGeneratorType, entityGeneratorImpl); services.AddSingleton <ITemplateFileService, FileSystemTemplateFileService>(); services.AddSingleton <IDbContextTemplateService, HbsDbContextTemplateService>(); services.AddSingleton <IEntityTypeTemplateService, HbsEntityTypeTemplateService>(); services.AddSingleton <IScaffoldingCodeGenerator, HbsCSharpScaffoldingGenerator>(); return(services); }
public async void ReverseEngineerCodeFirst(Project project) { try { var dteH = new EnvDteHelper(); var revEng = new EfCoreReverseEngineer(); string dacpacSchema = null; if (_package.Dte2.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var startTime = DateTime.Now; var projectPath = project.Properties.Item("FullPath").Value.ToString(); var optionsPath = Path.Combine(projectPath, "efpt.config.json"); var renamingPath = Path.Combine(projectPath, "efpt.renaming.json"); var databaseList = EnvDteHelper.GetDataConnections(_package); var dacpacList = _package.Dte2.DTE.GetDacpacFilesInActiveSolution(); var psd = _package.GetView <IPickServerDatabaseDialog>(); if (databaseList != null && databaseList.Any()) { psd.PublishConnections(databaseList.Select(m => new DatabaseConnectionModel { ConnectionName = m.Value.Caption, ConnectionString = m.Value.ConnectionString, DatabaseType = m.Value.DatabaseType })); } if (dacpacList != null && dacpacList.Any()) { psd.PublishDefinitions(dacpacList.Select(m => new DatabaseDefinitionModel { FilePath = m })); } var pickDataSourceResult = psd.ShowAndAwaitUserResponse(true); if (!pickDataSourceResult.ClosedByOK) { return; } _package.Dte2.StatusBar.Text = "Loading schema information..."; // Reload the database list, in case the user has added a new database in the dialog databaseList = EnvDteHelper.GetDataConnections(_package); DatabaseInfo dbInfo = null; if (pickDataSourceResult.Payload.Connection != null) { dbInfo = databaseList.Single(m => m.Value.ConnectionString == pickDataSourceResult.Payload.Connection?.ConnectionString).Value; } var dacpacPath = pickDataSourceResult.Payload.Definition?.FilePath; if (dbInfo == null) { dbInfo = new DatabaseInfo(); } if (!string.IsNullOrEmpty(dacpacPath)) { dbInfo.DatabaseType = DatabaseType.SQLServer; dbInfo.ConnectionString = "Data Source=.;Initial Catalog=" + Path.GetFileNameWithoutExtension(dacpacPath); dacpacPath = _package.Dte2.DTE.BuildSqlProj(dacpacPath); if (string.IsNullOrEmpty(dacpacPath)) { EnvDteHelper.ShowMessage("Unable to build selected Database Project"); return; } } if (dbInfo.DatabaseType == DatabaseType.SQLCE35) { EnvDteHelper.ShowError($"Unsupported provider: {dbInfo.ServerVersion}"); return; } var options = ReverseEngineerOptionsExtensions.TryRead(optionsPath); var predefinedTables = !string.IsNullOrEmpty(dacpacPath) ? revEng.GetDacpacTables(dacpacPath) : GetTablesFromRepository(dbInfo); var preselectedTables = new List <TableInformationModel>(); if (options != null) { dacpacSchema = options.DefaultDacpacSchema; if (options.Tables.Count > 0) { preselectedTables.AddRange(options.Tables); } } var ptd = _package.GetView <IPickTablesDialog>() .AddTables(predefinedTables) .PreselectTables(preselectedTables); var customNameOptions = CustomNameOptionsExtensions.TryRead(renamingPath); var pickTablesResult = ptd.ShowAndAwaitUserResponse(true); if (!pickTablesResult.ClosedByOK) { return; } var classBasis = string.Empty; if (dbInfo.DatabaseType == DatabaseType.Npgsql) { classBasis = EnvDteHelper.GetNpgsqlDatabaseName(dbInfo.ConnectionString); } else if (dbInfo.DatabaseType == DatabaseType.Mysql) { classBasis = EnvDteHelper.GetMysqlDatabaseName(dbInfo.ConnectionString); } else { classBasis = RepositoryHelper.GetClassBasis(dbInfo.ConnectionString, dbInfo.DatabaseType); } var model = revEng.GenerateClassName(classBasis) + "Context"; var packageResult = project.ContainsEfCoreReference(dbInfo.DatabaseType); var presets = new ModelingOptionsModel { InstallNuGetPackage = !packageResult.Item1, ModelName = options != null ? options.ContextClassName : model, ProjectName = project.Name, Namespace = options != null ? options.ProjectRootNamespace : project.Properties.Item("DefaultNamespace").Value.ToString(), DacpacPath = dacpacPath, }; if (options != null) { presets.UseDataAnnotations = !options.UseFluentApiOnly; presets.UseDatabaseNames = options.UseDatabaseNames; presets.UsePluralizer = options.UseInflector; presets.UseHandelbars = options.UseHandleBars; presets.SelectedHandlebarsLanguage = options.SelectedHandlebarsLanguage; presets.ReplaceId = options.IdReplace; presets.DoNotCombineNamespace = options.DoNotCombineNamespace; presets.IncludeConnectionString = options.IncludeConnectionString; presets.ModelName = options.ContextClassName; presets.Namespace = options.ProjectRootNamespace; presets.OutputPath = options.OutputPath; presets.SelectedToBeGenerated = options.SelectedToBeGenerated; } var modelDialog = _package.GetView <IModelingOptionsDialog>() .ApplyPresets(presets); _package.Dte2.StatusBar.Text = "Getting options..."; var modelingOptionsResult = modelDialog.ShowAndAwaitUserResponse(true); if (!modelingOptionsResult.ClosedByOK) { return; } options = new ReverseEngineerOptions { UseFluentApiOnly = !modelingOptionsResult.Payload.UseDataAnnotations, ConnectionString = dbInfo.ConnectionString, ContextClassName = modelingOptionsResult.Payload.ModelName, DatabaseType = (ReverseEngineer20.DatabaseType)dbInfo.DatabaseType, ProjectPath = projectPath, OutputPath = modelingOptionsResult.Payload.OutputPath, ProjectRootNamespace = modelingOptionsResult.Payload.Namespace, UseDatabaseNames = modelingOptionsResult.Payload.UseDatabaseNames, UseInflector = modelingOptionsResult.Payload.UsePluralizer, UseLegacyPluralizer = options?.UseLegacyPluralizer ?? false, IdReplace = modelingOptionsResult.Payload.ReplaceId, DoNotCombineNamespace = modelingOptionsResult.Payload.DoNotCombineNamespace, UseHandleBars = modelingOptionsResult.Payload.UseHandelbars, SelectedHandlebarsLanguage = modelingOptionsResult.Payload.SelectedHandlebarsLanguage, IncludeConnectionString = modelingOptionsResult.Payload.IncludeConnectionString, SelectedToBeGenerated = modelingOptionsResult.Payload.SelectedToBeGenerated, Dacpac = dacpacPath, DefaultDacpacSchema = dacpacSchema, Tables = pickTablesResult.Payload.ToList(), CustomReplacers = customNameOptions }; _package.Dte2.StatusBar.Text = "Generating code..."; var tfm = project.Properties.Item("TargetFrameworkMoniker").Value.ToString(); bool isNetStandard = tfm.Contains(".NETStandard,Version=v2.0"); if (modelingOptionsResult.Payload.UseHandelbars) { var dropped = (DropTemplates(projectPath)); if (dropped && !project.IsNetCore() && !isNetStandard) { project.ProjectItems.AddFromDirectory(Path.Combine(projectPath, "CodeTemplates")); } } var revEngResult = revEng.GenerateFiles(options); if (modelingOptionsResult.Payload.SelectedToBeGenerated == 0 || modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { project.ProjectItems.AddFromFile(filePath); } if (modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { if (File.Exists(revEngResult.ContextFilePath)) { File.Delete(revEngResult.ContextFilePath); } } } if (modelingOptionsResult.Payload.SelectedToBeGenerated == 0 || modelingOptionsResult.Payload.SelectedToBeGenerated == 1) { project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); if (!project.IsNetCore() && !isNetStandard) { _package.Dte2.ItemOperations.OpenFile(revEngResult.ContextFilePath); } if (modelingOptionsResult.Payload.SelectedToBeGenerated == 1) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { if (File.Exists(filePath)) { File.Delete(filePath); } } } } var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelingOptionsResult.Payload.InstallNuGetPackage || modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { missingProviderPackage = null; } _package.Dte2.StatusBar.Text = "Reporting result..."; var errors = ReportRevEngErrors(revEngResult, missingProviderPackage); SaveOptions(project, optionsPath, options); if (modelingOptionsResult.Payload.InstallNuGetPackage) { _package.Dte2.StatusBar.Text = "Installing EF Core provider package"; var nuGetHelper = new NuGetHelper(); await nuGetHelper.InstallPackageAsync(packageResult.Item2, project); } var duration = DateTime.Now - startTime; _package.Dte2.StatusBar.Text = $"Reverse engineer completed in {duration:h\\:mm\\:ss}"; EnvDteHelper.ShowMessage(errors); if (revEngResult.EntityErrors.Count > 0) { _package.LogError(revEngResult.EntityErrors, null); } if (revEngResult.EntityWarnings.Count > 0) { _package.LogError(revEngResult.EntityWarnings, null); } Telemetry.TrackEvent("PowerTools.ReverseEngineer"); } catch (AggregateException ae) { foreach (var innerException in ae.Flatten().InnerExceptions) { _package.LogError(new List <string>(), innerException); } } catch (Exception exception) { _package.LogError(new List <string>(), exception); } }
public async void ReverseEngineerCodeFirst(Project project) { try { var dteH = new EnvDteHelper(); var revEng = new EfCoreReverseEngineer(); string dacpacSchema = null; if (_package.Dte2.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var startTime = DateTime.Now; var projectPath = project.Properties.Item("FullPath").Value.ToString(); var optionsPath = Path.Combine(projectPath, "efpt.config.json"); var databaseList = EnvDteHelper.GetDataConnections(_package); var dacpacList = _package.Dte2.DTE.GetDacpacFilesInActiveSolution(); var psd = new PickServerDatabaseDialog(databaseList, _package, dacpacList); if (psd.ShowModal() != true) { return; } _package.Dte2.StatusBar.Text = "Loading schema information..."; var dbInfo = psd.SelectedDatabase.Value; var dacpacPath = psd.DacpacPath; if (dbInfo == null) { dbInfo = new DatabaseInfo(); } if (!string.IsNullOrEmpty(dacpacPath)) { dbInfo.DatabaseType = DatabaseType.SQLServer; dbInfo.ConnectionString = "Data Source=.;Initial Catalog=" + Path.GetFileNameWithoutExtension(dacpacPath); dacpacPath = _package.Dte2.DTE.BuildSqlProj(dacpacPath); if (string.IsNullOrEmpty(dacpacPath)) { EnvDteHelper.ShowMessage("Unable to build selected Database Project"); return; } } if (dbInfo.DatabaseType == DatabaseType.SQLCE35) { EnvDteHelper.ShowError($"Unsupported provider: {dbInfo.ServerVersion}"); return; } var ptd = new PickTablesDialog { IncludeTables = true }; if (!string.IsNullOrEmpty(dacpacPath)) { ptd.Tables = revEng.GetDacpacTableNames(dacpacPath); } else { ptd.Tables = GetTablesFromRepository(dbInfo); } var options = ReverseEngineerOptionsExtensions.TryRead(optionsPath); if (options != null) { dacpacSchema = options.DefaultDacpacSchema; if (options.Tables.Count > 0) { ptd.SelectedTables = options.Tables; } } if (ptd.ShowModal() != true) { return; } var classBasis = string.Empty; if (dbInfo.DatabaseType == DatabaseType.Npgsql) { classBasis = EnvDteHelper.GetNpgsqlDatabaseName(dbInfo.ConnectionString); } else { classBasis = RepositoryHelper.GetClassBasis(dbInfo.ConnectionString, dbInfo.DatabaseType); } var model = revEng.GenerateClassName(classBasis) + "Context"; var packageResult = project.ContainsEfCoreReference(dbInfo.DatabaseType); var modelDialog = new EfCoreModelDialog(options) { InstallNuGetPackage = !packageResult.Item1, ModelName = options != null ? options.ContextClassName : model, ProjectName = project.Name, NameSpace = options != null ? options.ProjectRootNamespace : project.Properties.Item("DefaultNamespace").Value.ToString(), DacpacPath = dacpacPath }; _package.Dte2.StatusBar.Text = "Getting options..."; if (modelDialog.ShowModal() != true) { return; } options = new ReverseEngineerOptions { UseFluentApiOnly = !modelDialog.UseDataAnnotations, ConnectionString = dbInfo.ConnectionString, ContextClassName = modelDialog.ModelName, DatabaseType = (ReverseEngineer20.DatabaseType)dbInfo.DatabaseType, ProjectPath = projectPath, OutputPath = modelDialog.OutputPath, ProjectRootNamespace = modelDialog.NameSpace, UseDatabaseNames = modelDialog.UseDatabaseNames, UseInflector = modelDialog.UsePluralizer, IdReplace = modelDialog.ReplaceId, UseHandleBars = modelDialog.UseHandelbars, IncludeConnectionString = modelDialog.IncludeConnectionString, SelectedToBeGenerated = modelDialog.SelectedTobeGenerated, Dacpac = dacpacPath, DefaultDacpacSchema = dacpacSchema, Tables = ptd.Tables }; _package.Dte2.StatusBar.Text = "Generating code..."; var tfm = project.Properties.Item("TargetFrameworkMoniker").Value.ToString(); bool isNetCore = tfm.Contains(".NETCoreApp,Version=v2.0"); bool isNetStandard = tfm.Contains(".NETStandard,Version=v2.0"); //TODO await update //if (modelDialog.UseHandelbars) //{ // var dropped = (DropTemplates(projectPath)); // if (dropped && !isNetCore && !isNetStandard) // { // project.ProjectItems.AddFromDirectory(Path.Combine(projectPath, "CodeTemplates")); // } //} var revEngResult = revEng.GenerateFiles(options); if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { project.ProjectItems.AddFromFile(filePath); } if (modelDialog.SelectedTobeGenerated == 2) { if (File.Exists(revEngResult.ContextFilePath)) { File.Delete(revEngResult.ContextFilePath); } } } if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 1) { project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); if (!isNetCore && !isNetStandard) { _package.Dte2.ItemOperations.OpenFile(revEngResult.ContextFilePath); } if (modelDialog.SelectedTobeGenerated == 1) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { if (File.Exists(filePath)) { File.Delete(filePath); } } } } var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelDialog.InstallNuGetPackage) { missingProviderPackage = null; } _package.Dte2.StatusBar.Text = "Reporting result..."; var errors = ReportRevEngErrors(revEngResult, missingProviderPackage); SaveOptions(project, optionsPath, options); if (modelDialog.InstallNuGetPackage) { _package.Dte2.StatusBar.Text = "Installing EF Core provider package"; var nuGetHelper = new NuGetHelper(); await nuGetHelper.InstallPackageAsync(packageResult.Item2, project); } var duration = DateTime.Now - startTime; _package.Dte2.StatusBar.Text = $"Reverse engineer completed in {duration:h\\:mm\\:ss}"; EnvDteHelper.ShowMessage(errors); if (revEngResult.EntityErrors.Count > 0) { _package.LogError(revEngResult.EntityErrors, null); } if (revEngResult.EntityWarnings.Count > 0) { _package.LogError(revEngResult.EntityWarnings, null); } Telemetry.TrackEvent("PowerTools.ReverseEngineer"); } catch (AggregateException ae) { foreach (var innerException in ae.Flatten().InnerExceptions) { _package.LogError(new List <string>(), innerException); } } catch (Exception exception) { _package.LogError(new List <string>(), exception); } }
public string GetReadMeText(ReverseEngineerOptions options, string content) { return(content.Replace("[ProviderName]", GetProviderName(options.DatabaseType)) .Replace("[ConnectionString]", options.ConnectionString) .Replace("[ContextName]", options.ContextClassName)); }
private IReverseEngineerScaffolder CreateScaffolder(ReverseEngineerOptions revEngOptions, string filenamePrefix = null) { return(CreateScaffolder(revEngOptions, _ => { }, filenamePrefix)); }
private IReverseEngineerScaffolder CreateScaffolder(ReverseEngineerOptions revEngOptions, Action <HandlebarsScaffoldingOptions> configureOptions, string filenamePrefix = null) { var fileService = new InMemoryTemplateFileService(); fileService.InputFiles(ContextClassTemplate, ContextImportsTemplate, ContextCtorTemplate, ContextOnConfiguringTemplate, ContextDbSetsTemplate, EntityClassTemplate, EntityImportsTemplate, EntityCtorTemplate, EntityPropertiesTemplate); var services = new ServiceCollection() .AddEntityFrameworkDesignTimeServices() .AddSingleton <IDbContextTemplateService, FakeHbsDbContextTemplateService>() .AddSingleton <IEntityTypeTemplateService, FakeHbsEntityTypeTemplateService>() .AddSingleton <ITemplateFileService>(fileService) .AddSingleton <ITemplateLanguageService, FakeCSharpTemplateLanguageService>() .AddSingleton <IModelCodeGenerator, HbsCSharpModelGenerator>(); #pragma warning disable EF1001 // Internal EF Core API usage. services .AddSingleton(provider => { ICSharpDbContextGenerator contextGenerator = new HbsCSharpDbContextGenerator( provider.GetRequiredService <IProviderConfigurationCodeGenerator>(), provider.GetRequiredService <IAnnotationCodeGenerator>(), provider.GetRequiredService <IDbContextTemplateService>(), provider.GetRequiredService <IEntityTypeTransformationService>(), provider.GetRequiredService <ICSharpHelper>(), provider.GetRequiredService <IOptions <HandlebarsScaffoldingOptions> >()); return(revEngOptions == ReverseEngineerOptions.DbContextOnly || revEngOptions == ReverseEngineerOptions.DbContextAndEntities ? contextGenerator : new NullCSharpDbContextGenerator()); }) .AddSingleton(provider => { ICSharpEntityTypeGenerator entityGenerator = new HbsCSharpEntityTypeGenerator( provider.GetRequiredService <IAnnotationCodeGenerator>(), provider.GetRequiredService <ICSharpHelper>(), provider.GetRequiredService <IEntityTypeTemplateService>(), provider.GetRequiredService <IEntityTypeTransformationService>(), provider.GetRequiredService <IOptions <HandlebarsScaffoldingOptions> >()); return(revEngOptions == ReverseEngineerOptions.EntitiesOnly || revEngOptions == ReverseEngineerOptions.DbContextAndEntities ? entityGenerator : new NullCSharpEntityTypeGenerator()); }); #pragma warning restore EF1001 // Internal EF Core API usage. services .AddSingleton <IHbsHelperService>(provider => new HbsHelperService(new Dictionary <string, Action <TextWriter, Dictionary <string, object>, object[]> > { { EntityFrameworkCore.Scaffolding.Handlebars.Helpers.Constants.SpacesHelper, HandlebarsHelpers.SpacesHelper } })) .AddSingleton <IHbsBlockHelperService>(provider => new HbsBlockHelperService(new Dictionary <string, Action <TextWriter, HelperOptions, Dictionary <string, object>, object[]> >())) .AddSingleton <IReverseEngineerScaffolder, HbsReverseEngineerScaffolder>(); if (string.IsNullOrWhiteSpace(filenamePrefix)) { services .AddSingleton <IContextTransformationService, HbsContextTransformationService>() .AddSingleton <IEntityTypeTransformationService, HbsEntityTypeTransformationService>(); } else { services .AddSingleton <IContextTransformationService>(y => new HbsContextTransformationService(contextName => $"{filenamePrefix}{contextName}")) .AddSingleton <IEntityTypeTransformationService>(y => new HbsEntityTypeTransformationService(entityFileNameTransformer: entityName => $"{filenamePrefix}{entityName}")); } services.Configure(configureOptions); #pragma warning disable EF1001 // Internal EF Core API usage. new SqlServerDesignTimeServices().ConfigureDesignTimeServices(services); #pragma warning restore EF1001 // Internal EF Core API usage. var scaffolder = services .BuildServiceProvider() .GetRequiredService <IReverseEngineerScaffolder>(); return(scaffolder); }
public void ReverseEngineerCodeFirst(Project project) { try { if (_package.Dte2.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var startTime = DateTime.Now; // Show dialog with SqlClient selected by default var dialogFactory = _package.GetService <IVsDataConnectionDialogFactory>(); var dialog = dialogFactory.CreateConnectionDialog(); dialog.AddAllSources(); dialog.SelectedSource = new Guid("067ea0d9-ba62-43f7-9106-34930c60c528"); var dialogResult = dialog.ShowDialog(connect: true); if (dialogResult != null) { _package.Dte2.StatusBar.Text = "Loading schema information..."; // Find connection string and provider var connection = (DbConnection)dialogResult.GetLockedProviderObject(); var connectionString = connection.ConnectionString; var providerManager = (IVsDataProviderManager)Package.GetGlobalService(typeof(IVsDataProviderManager)); IVsDataProvider dp; providerManager.Providers.TryGetValue(dialogResult.Provider, out dp); var providerInvariant = (string)dp.GetProperty("InvariantName"); var dbType = DatabaseType.SQLCE35; if (providerInvariant == "System.Data.SqlServerCe.4.0") { dbType = DatabaseType.SQLCE40; } if (providerInvariant == "System.Data.SQLite.EF6") { dbType = DatabaseType.SQLite; } if (providerInvariant == "System.Data.SqlClient") { dbType = DatabaseType.SQLServer; } if (dbType == DatabaseType.SQLCE35) { EnvDteHelper.ShowError($"Unsupported provider: {providerInvariant}"); return; } var ptd = new PickTablesDialog { IncludeTables = true }; using (var repository = RepositoryHelper.CreateRepository(new DatabaseInfo { ConnectionString = connectionString, DatabaseType = dbType })) { ptd.Tables = repository.GetAllTableNamesForExclusion(); } var res = ptd.ShowModal(); if (!res.HasValue || !res.Value) { return; } var classBasis = RepositoryHelper.GetClassBasis(connectionString, dbType); var dteH = new EnvDteHelper(); var revEng = new EfCoreReverseEngineer(); var model = revEng.GenerateClassName(classBasis) + "Context"; var packageResult = dteH.ContainsEfCoreReference(project, dbType); var modelDialog = new EfCoreModelDialog { InstallNuGetPackage = !packageResult.Item1, ModelName = model, ProjectName = project.Name, NameSpace = project.Properties.Item("DefaultNamespace").Value.ToString() }; _package.Dte2.StatusBar.Text = "Getting options..."; var result = modelDialog.ShowModal(); if (!result.HasValue || result.Value != true) { return; } var projectPath = project.Properties.Item("FullPath").Value.ToString(); var options = new ReverseEngineerOptions { UseFluentApiOnly = !modelDialog.UseDataAnnotations, ConnectionString = connectionString, ContextClassName = modelDialog.ModelName, DatabaseType = (EFCoreReverseEngineer.DatabaseType)dbType, ProjectPath = projectPath, OutputPath = modelDialog.OutputPath, ProjectRootNamespace = modelDialog.NameSpace, UseDatabaseNames = modelDialog.UseDatabaseNames, Tables = ptd.Tables }; _package.Dte2.StatusBar.Text = "Generating code..."; var revEngResult = revEng.GenerateFiles(options); if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { project.ProjectItems.AddFromFile(filePath); } } if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 1) { project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); _package.Dte2.ItemOperations.OpenFile(revEngResult.ContextFilePath); } packageResult = dteH.ContainsEfCoreReference(project, dbType); var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelDialog.InstallNuGetPackage) { missingProviderPackage = null; } _package.Dte2.StatusBar.Text = "Reporting result..."; var errors = ReportRevEngErrors(revEngResult, missingProviderPackage); if (modelDialog.InstallNuGetPackage) { _package.Dte2.StatusBar.Text = "Installing EF Core provider package"; var nuGetHelper = new NuGetHelper(); nuGetHelper.InstallPackage(packageResult.Item2, project); } var duration = DateTime.Now - startTime; _package.Dte2.StatusBar.Text = $"Reverse engineer completed in {duration:h\\:mm\\:ss}"; EnvDteHelper.ShowMessage(errors); if (revEngResult.EntityErrors.Count > 0) { _package.LogError(revEngResult.EntityErrors, null); } if (revEngResult.EntityWarnings.Count > 0) { _package.LogError(revEngResult.EntityWarnings, null); } } } catch (Exception exception) { _package.LogError(new List <string>(), exception); } }
public void GenerateEfCoreModelInProject(object sender, ExecutedRoutedEventArgs e) { var databaseInfo = ValidateMenuInfo(sender); if (databaseInfo == null) { return; } var dbType = databaseInfo.DatabaseInfo.DatabaseType; var dte = package?.GetServiceHelper(typeof(DTE)) as DTE; if (dte == null) { return; } if (dte.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var dteH = new EnvDteHelper(); var project = dteH.GetProject(dte); if (project == null) { EnvDteHelper.ShowError("Please select a project in Solution Explorer, where you want the EF Core Model to be placed"); return; } try { var ptd = new PickTablesDialog { IncludeTables = true }; using (var repository = DataConnectionHelper.CreateRepository(new DatabaseInfo { ConnectionString = databaseInfo.DatabaseInfo.ConnectionString, DatabaseType = databaseInfo.DatabaseInfo.DatabaseType })) { ptd.Tables = repository.GetAllTableNamesForExclusion(); } var res = ptd.ShowModal(); if (!res.HasValue || !res.Value) { return; } var revEng = new EFCoreReverseEngineer.EfCoreReverseEngineer(); var classBasis = Path.GetFileNameWithoutExtension(databaseInfo.DatabaseInfo.Caption); if (dbType == DatabaseType.SQLServer) { classBasis = new SqlConnectionStringBuilder(databaseInfo.DatabaseInfo.ConnectionString).InitialCatalog; } var model = revEng.GenerateClassName(classBasis) + "Context"; var modelDialog = new EfCoreModelDialog { ModelName = model, ProjectName = project.Name, NameSpace = project.Properties.Item("DefaultNamespace").Value.ToString() }; var result = modelDialog.ShowModal(); if (!result.HasValue || result.Value != true) { return; } var projectPath = project.Properties.Item("FullPath").Value.ToString(); var options = new ReverseEngineerOptions { UseFluentApiOnly = !modelDialog.UseDataAnnotations, ConnectionString = databaseInfo.DatabaseInfo.ConnectionString, ContextClassName = modelDialog.ModelName, DatabaseType = (EFCoreReverseEngineer.DatabaseType)dbType, ProjectPath = projectPath, OutputPath = modelDialog.OutputPath, ProjectRootNamespace = modelDialog.NameSpace, Tables = ptd.Tables }; var revEngResult = revEng.GenerateFiles(options); foreach (var filePath in revEngResult.FilePaths) { project.ProjectItems.AddFromFile(filePath); } if (revEngResult.FilePaths.Count > 0) { dte.ItemOperations.OpenFile(revEngResult.FilePaths.Last()); } ReportRevEngErrors(revEngResult, dteH.ContainsEfCoreReference(project, dbType)); DataConnectionHelper.LogUsage("DatabaseCreateEfCoreModel"); } catch (Exception ex) { DataConnectionHelper.SendError(ex, databaseInfo.DatabaseInfo.DatabaseType, false); } }
public async void ReverseEngineerCodeFirst(Project project) { try { if (_package.Dte2.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var startTime = DateTime.Now; var databaseList = EnvDteHelper.GetDataConnections(_package); var psd = new PickServerDatabaseDialog(databaseList, _package); var diagRes = psd.ShowModal(); if (!diagRes.HasValue || !diagRes.Value) { return; } // Show dialog with SqlClient selected by default _package.Dte2.StatusBar.Text = "Loading schema information..."; var dbInfo = psd.SelectedDatabase.Value; if (dbInfo.DatabaseType == DatabaseType.SQLCE35) { EnvDteHelper.ShowError($"Unsupported provider: {dbInfo.ServerVersion}"); return; } var ptd = new PickTablesDialog { IncludeTables = true }; using (var repository = RepositoryHelper.CreateRepository(dbInfo)) { ptd.Tables = repository.GetAllTableNamesForExclusion(); } var res = ptd.ShowModal(); if (!res.HasValue || !res.Value) { return; } var classBasis = RepositoryHelper.GetClassBasis(dbInfo.ConnectionString, dbInfo.DatabaseType); var dteH = new EnvDteHelper(); var revEng = new EfCoreReverseEngineer(); var model = revEng.GenerateClassName(classBasis) + "Context"; var packageResult = dteH.ContainsEfCoreReference(project, dbInfo.DatabaseType); var modelDialog = new EfCoreModelDialog { InstallNuGetPackage = !packageResult.Item1, ModelName = model, ProjectName = project.Name, NameSpace = project.Properties.Item("DefaultNamespace").Value.ToString() }; _package.Dte2.StatusBar.Text = "Getting options..."; var result = modelDialog.ShowModal(); if (!result.HasValue || result.Value != true) { return; } var projectPath = project.Properties.Item("FullPath").Value.ToString(); var options = new ReverseEngineerOptions { UseFluentApiOnly = !modelDialog.UseDataAnnotations, ConnectionString = dbInfo.ConnectionString, ContextClassName = modelDialog.ModelName, DatabaseType = (ReverseEngineer20.DatabaseType)dbInfo.DatabaseType, ProjectPath = projectPath, OutputPath = modelDialog.OutputPath, ProjectRootNamespace = modelDialog.NameSpace, UseDatabaseNames = modelDialog.UseDatabaseNames, UseInflector = modelDialog.UsePluralizer, IdReplace = modelDialog.ReplaceId, UseHandleBars = modelDialog.UseHandelbars, Tables = ptd.Tables }; _package.Dte2.StatusBar.Text = "Generating code..."; if (modelDialog.UseHandelbars) { if (DropTemplates(projectPath)) { project.ProjectItems.AddFromDirectory(Path.Combine(projectPath, "CodeTemplates")); } } var revEngResult = revEng.GenerateFiles(options); if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { project.ProjectItems.AddFromFile(filePath); } } if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 1) { project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); _package.Dte2.ItemOperations.OpenFile(revEngResult.ContextFilePath); } packageResult = dteH.ContainsEfCoreReference(project, dbInfo.DatabaseType); var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelDialog.InstallNuGetPackage) { missingProviderPackage = null; } _package.Dte2.StatusBar.Text = "Reporting result..."; var errors = ReportRevEngErrors(revEngResult, missingProviderPackage); if (modelDialog.InstallNuGetPackage) { _package.Dte2.StatusBar.Text = "Installing EF Core provider package"; var nuGetHelper = new NuGetHelper(); await nuGetHelper.InstallPackageAsync(packageResult.Item2, project); } var duration = DateTime.Now - startTime; _package.Dte2.StatusBar.Text = $"Reverse engineer completed in {duration:h\\:mm\\:ss}"; EnvDteHelper.ShowMessage(errors); if (revEngResult.EntityErrors.Count > 0) { _package.LogError(revEngResult.EntityErrors, null); } if (revEngResult.EntityWarnings.Count > 0) { _package.LogError(revEngResult.EntityWarnings, null); } Telemetry.TrackEvent("PowerTools.ReverseEngineer"); } catch (AggregateException ae) { foreach (var innerException in ae.Flatten().InnerExceptions) { _package.LogError(new List <string>(), innerException); } } catch (Exception exception) { _package.LogError(new List <string>(), exception); } }
public async System.Threading.Tasks.Task ReverseEngineerCodeFirstAsync(Project project) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); try { var dteH = new EnvDteHelper(); string dacpacSchema = null; if (_package.Dte2.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var projectPath = project.Properties.Item("FullPath")?.Value.ToString(); var optionsPaths = project.GetConfigFiles(); var optionsPath = optionsPaths.First(); var renamingPath = project.GetRenamingPath(); if (optionsPaths.Count > 1) { var pcd = _package.GetView <IPickConfigDialog>(); pcd.PublishConfigurations(optionsPaths.Select(m => new ConfigModel { ConfigPath = m, })); var pickConfigResult = pcd.ShowAndAwaitUserResponse(true); if (!pickConfigResult.ClosedByOK) { return; } optionsPath = pickConfigResult.Payload.ConfigPath; } var databaseList = VsDataHelper.GetDataConnections(_package); var dacpacList = _package.Dte2.DTE.GetDacpacFilesInActiveSolution(EnvDteHelper.GetProjectFilesInSolution(_package)); var options = ReverseEngineerOptionsExtensions.TryRead(optionsPath); var psd = _package.GetView <IPickServerDatabaseDialog>(); if (databaseList != null && databaseList.Any()) { psd.PublishConnections(databaseList.Select(m => new DatabaseConnectionModel { ConnectionName = m.Value.Caption, ConnectionString = m.Value.ConnectionString, DatabaseType = m.Value.DatabaseType, DataConnection = m.Value.DataConnection, })); } if (dacpacList != null && dacpacList.Any()) { psd.PublishDefinitions(dacpacList.Select(m => new DatabaseDefinitionModel { FilePath = m })); } if (options != null && options.FilterSchemas && options.Schemas != null && options.Schemas.Any()) { psd.PublishSchemas(options.Schemas); } if (options != null) { psd.PublishCodeGenerationMode(options.CodeGenerationMode); } var pickDataSourceResult = psd.ShowAndAwaitUserResponse(true); if (!pickDataSourceResult.ClosedByOK) { return; } var useEFCore5 = pickDataSourceResult.Payload.IncludeViews; var filterSchemas = pickDataSourceResult.Payload.FilterSchemas; var schemas = filterSchemas ? pickDataSourceResult.Payload.Schemas : null; _package.Dte2.StatusBar.Text = "Getting ready to connect..."; // Reload the database list, in case the user has added a new database in the dialog databaseList = VsDataHelper.GetDataConnections(_package); DatabaseInfo dbInfo = null; if (pickDataSourceResult.Payload.Connection != null) { dbInfo = databaseList.Single(m => m.Value.ConnectionString == pickDataSourceResult.Payload.Connection?.ConnectionString).Value; } var dacpacPath = pickDataSourceResult.Payload.Definition?.FilePath; if (dbInfo == null) { dbInfo = new DatabaseInfo(); } if (!string.IsNullOrEmpty(dacpacPath)) { dbInfo.DatabaseType = DatabaseType.SQLServerDacpac; dbInfo.ConnectionString = $"Data Source=(local);Initial Catalog={Path.GetFileNameWithoutExtension(dacpacPath)};Integrated Security=true;"; dacpacPath = _package.Dte2.DTE.BuildSqlProj(dacpacPath); if (string.IsNullOrEmpty(dacpacPath)) { EnvDteHelper.ShowMessage("Unable to build selected Database Project"); return; } } if (dbInfo.DatabaseType == DatabaseType.SQLCE35 || dbInfo.DatabaseType == DatabaseType.SQLCE40 || dbInfo.DatabaseType == DatabaseType.Undefined) { EnvDteHelper.ShowError($"Unsupported provider: {dbInfo.ServerVersion}"); return; } //TODO Enable when Oracle EF Core 5 provider is released if (useEFCore5 && (dbInfo.DatabaseType == DatabaseType.Oracle)) { EnvDteHelper.ShowError($"Unsupported provider with EF Core 5.0: {dbInfo.DatabaseType}"); return; } _package.Dte2.StatusBar.Text = "Loading database objects..."; object icon = (short)Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Build; _package.Dte2.StatusBar.Animate(true, icon); var predefinedTables = !string.IsNullOrEmpty(dacpacPath) ? await GetDacpacTablesAsync(dacpacPath, useEFCore5) : await GetTablesAsync(dbInfo, useEFCore5, schemas); _package.Dte2.StatusBar.Animate(false, icon); var preselectedTables = new List <SerializationTableModel>(); if (options != null) { dacpacSchema = options.DefaultDacpacSchema; if (options.Tables.Count > 0) { var normalizedTables = reverseEngineerHelper.NormalizeTables(options.Tables, dbInfo.DatabaseType == DatabaseType.SQLServer); preselectedTables.AddRange(normalizedTables); } } var namingOptionsAndPath = CustomNameOptionsExtensions.TryRead(renamingPath, optionsPath); _package.Dte2.StatusBar.Clear(); var ptd = _package.GetView <IPickTablesDialog>() .AddTables(predefinedTables, namingOptionsAndPath.Item1) .PreselectTables(preselectedTables); var pickTablesResult = ptd.ShowAndAwaitUserResponse(true); if (!pickTablesResult.ClosedByOK) { return; } _package.Dte2.StatusBar.Text = "Loading options..."; var classBasis = VsDataHelper.GetDatabaseName(dbInfo.ConnectionString, dbInfo.DatabaseType); var model = reverseEngineerHelper.GenerateClassName(classBasis) + "Context"; var packageResult = project.ContainsEfCoreReference(dbInfo.DatabaseType); var presets = new ModelingOptionsModel { InstallNuGetPackage = !packageResult.Item1, ModelName = options != null ? options.ContextClassName : model, ProjectName = project.Name, Namespace = options != null ? options.ProjectRootNamespace : project.Properties.Item("DefaultNamespace").Value.ToString(), DacpacPath = dacpacPath, }; if (options != null) { presets.UseDataAnnotations = !options.UseFluentApiOnly; presets.UseDatabaseNames = options.UseDatabaseNames; presets.UsePluralizer = options.UseInflector; presets.UseDbContextSplitting = options.UseDbContextSplitting; presets.UseHandlebars = options.UseHandleBars; presets.SelectedHandlebarsLanguage = options.SelectedHandlebarsLanguage; presets.IncludeConnectionString = options.IncludeConnectionString; presets.ModelName = options.ContextClassName; presets.Namespace = options.ProjectRootNamespace; presets.OutputPath = options.OutputPath; presets.OutputContextPath = options.OutputContextPath; presets.ModelNamespace = options.ModelNamespace; presets.ContextNamespace = options.ContextNamespace; presets.SelectedToBeGenerated = options.SelectedToBeGenerated; presets.DacpacPath = options.Dacpac; presets.UseEf6Pluralizer = options.UseLegacyPluralizer; presets.MapSpatialTypes = options.UseSpatial; presets.MapNodaTimeTypes = options.UseNodaTime; presets.UseBoolPropertiesWithoutDefaultSql = options.UseBoolPropertiesWithoutDefaultSql; presets.UseNoConstructor = options.UseNoConstructor; presets.UseNoNavigations = options.UseNoNavigations; presets.UseNullableReferences = options.UseNullableReferences; } var modelDialog = _package.GetView <IModelingOptionsDialog>() .ApplyPresets(presets); _package.Dte2.StatusBar.Clear(); var modelingOptionsResult = modelDialog.ShowAndAwaitUserResponse(true); if (!modelingOptionsResult.ClosedByOK) { return; } options = new ReverseEngineerOptions { UseFluentApiOnly = !modelingOptionsResult.Payload.UseDataAnnotations, ConnectionString = dbInfo.ConnectionString, ContextClassName = modelingOptionsResult.Payload.ModelName, DatabaseType = dbInfo.DatabaseType, ProjectPath = projectPath, OutputPath = modelingOptionsResult.Payload.OutputPath, OutputContextPath = modelingOptionsResult.Payload.OutputContextPath, ContextNamespace = modelingOptionsResult.Payload.ContextNamespace, ModelNamespace = modelingOptionsResult.Payload.ModelNamespace, ProjectRootNamespace = modelingOptionsResult.Payload.Namespace, UseDatabaseNames = modelingOptionsResult.Payload.UseDatabaseNames, UseInflector = modelingOptionsResult.Payload.UsePluralizer, UseLegacyPluralizer = modelingOptionsResult.Payload.UseEf6Pluralizer, UseSpatial = modelingOptionsResult.Payload.MapSpatialTypes, UseNodaTime = modelingOptionsResult.Payload.MapNodaTimeTypes, UseDbContextSplitting = modelingOptionsResult.Payload.UseDbContextSplitting, UseHandleBars = modelingOptionsResult.Payload.UseHandlebars, SelectedHandlebarsLanguage = modelingOptionsResult.Payload.SelectedHandlebarsLanguage, IncludeConnectionString = modelingOptionsResult.Payload.IncludeConnectionString, SelectedToBeGenerated = modelingOptionsResult.Payload.SelectedToBeGenerated, UseBoolPropertiesWithoutDefaultSql = modelingOptionsResult.Payload.UseBoolPropertiesWithoutDefaultSql, UseNullableReferences = modelingOptionsResult.Payload.UseNullableReferences, UseNoConstructor = modelingOptionsResult.Payload.UseNoConstructor, UseNoNavigations = modelingOptionsResult.Payload.UseNoNavigations, Dacpac = dacpacPath, DefaultDacpacSchema = dacpacSchema, Tables = pickTablesResult.Payload.Objects.ToList(), CustomReplacers = pickTablesResult.Payload.CustomReplacers.ToList(), FilterSchemas = filterSchemas, Schemas = schemas?.ToList(), CodeGenerationMode = pickDataSourceResult.Payload.IncludeViews ? CodeGenerationMode.EFCore5 : CodeGenerationMode.EFCore3, }; if (options.DatabaseType == DatabaseType.SQLServer && string.IsNullOrEmpty(options.Dacpac)) { var rightsAndVersion = reverseEngineerHelper.HasSqlServerViewDefinitionRightsAndVersion(options.ConnectionString); if (rightsAndVersion.Item1 == false) { EnvDteHelper.ShowMessage("The SQL Server user does not have 'VIEW DEFINITION' rights, default constraints may not be available."); } if (rightsAndVersion.Item2.Major < 11) { EnvDteHelper.ShowMessage($"SQL Server version {rightsAndVersion.Item2} may not be supported."); } } var tfm = project.Properties.Item("TargetFrameworkMoniker").Value.ToString(); bool isNetStandard = tfm.Contains(".NETStandard,Version=v2."); if (modelingOptionsResult.Payload.UseHandlebars) { var dropped = (DropTemplates(projectPath, useEFCore5)); if (dropped && !project.IsNetCore() && !isNetStandard) { project.ProjectItems.AddFromDirectory(Path.Combine(projectPath, "CodeTemplates")); } } var startTime = DateTime.Now; _package.Dte2.StatusBar.Animate(true, icon); _package.Dte2.StatusBar.Text = "Generating code..."; var revEngResult = EfRevEngLauncher.LaunchExternalRunner(options, useEFCore5); _package.Dte2.StatusBar.Animate(false, icon); if (modelingOptionsResult.Payload.SelectedToBeGenerated == 0 || modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { if (!project.IsNetCore() && !isNetStandard) { project.ProjectItems.AddFromFile(filePath); } } if (modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { if (File.Exists(revEngResult.ContextFilePath)) { File.Delete(revEngResult.ContextFilePath); } foreach (var filePath in revEngResult.ContextConfigurationFilePaths) { if (File.Exists(filePath)) { File.Delete(filePath); } } } } if (modelingOptionsResult.Payload.SelectedToBeGenerated == 0 || modelingOptionsResult.Payload.SelectedToBeGenerated == 1) { if (!project.IsNetCore() && !isNetStandard) { foreach (var filePath in revEngResult.ContextConfigurationFilePaths) { project.ProjectItems.AddFromFile(filePath); } project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); } _package.Dte2.ItemOperations.OpenFile(revEngResult.ContextFilePath); if (modelingOptionsResult.Payload.SelectedToBeGenerated == 1) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { if (File.Exists(filePath)) { File.Delete(filePath); } } } } var duration = DateTime.Now - startTime; var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelingOptionsResult.Payload.InstallNuGetPackage || modelingOptionsResult.Payload.SelectedToBeGenerated == 2) { missingProviderPackage = null; } _package.Dte2.StatusBar.Text = "Reporting result..."; var errors = reverseEngineerHelper.ReportRevEngErrors(revEngResult, missingProviderPackage); SaveOptions(project, optionsPath, options, new Tuple <List <Schema>, string>(pickTablesResult.Payload.CustomReplacers.ToList(), namingOptionsAndPath.Item2)); if (modelingOptionsResult.Payload.InstallNuGetPackage) { _package.Dte2.StatusBar.Text = "Installing EF Core provider package"; var nuGetHelper = new NuGetHelper(); await nuGetHelper.InstallPackageAsync(packageResult.Item2, project); } _package.Dte2.StatusBar.Text = $"Reverse engineer completed in {duration:h\\:mm\\:ss}"; EnvDteHelper.ShowMessage(errors); if (revEngResult.EntityErrors.Count > 0) { _package.LogError(revEngResult.EntityErrors, null); } if (revEngResult.EntityWarnings.Count > 0) { _package.LogError(revEngResult.EntityWarnings, null); } Telemetry.TrackEvent("PowerTools.ReverseEngineer"); } catch (AggregateException ae) { foreach (var innerException in ae.Flatten().InnerExceptions) { _package.LogError(new List <string>(), innerException); } } catch (Exception exception) { _package.LogError(new List <string>(), exception); } }
public async void GenerateEfCoreModelInProject(object sender, ExecutedRoutedEventArgs e) { var databaseInfo = ValidateMenuInfo(sender); if (databaseInfo == null) { return; } var dbType = databaseInfo.DatabaseInfo.DatabaseType; var dte = package?.GetServiceHelper(typeof(DTE)) as DTE; if (dte == null) { return; } if (dte.Mode == vsIDEMode.vsIDEModeDebug) { EnvDteHelper.ShowError("Cannot generate code while debugging"); return; } var dteH = new EnvDteHelper(); var project = dteH.GetProject(dte); if (project == null) { EnvDteHelper.ShowError("Please select a project in Solution Explorer, where you want the EF Core Model to be placed"); return; } try { var ptd = new PickTablesDialog { IncludeTables = true }; using (var repository = Helpers.RepositoryHelper.CreateRepository(new DatabaseInfo { ConnectionString = databaseInfo.DatabaseInfo.ConnectionString, DatabaseType = databaseInfo.DatabaseInfo.DatabaseType })) { ptd.Tables = repository.GetAllTableNamesForExclusion(); } var res = ptd.ShowModal(); if (!res.HasValue || !res.Value) { return; } var revEng = new EfCoreReverseEngineer(); var classBasis = Helpers.RepositoryHelper.GetClassBasis(databaseInfo.DatabaseInfo.ConnectionString, dbType); var model = revEng.GenerateClassName(classBasis) + "Context"; var packageResult = dteH.ContainsEfCoreReference(project, dbType); var modelDialog = new EfCoreModelDialog { InstallNuGetPackage = !packageResult.Item1, ModelName = model, ProjectName = project.Name, NameSpace = project.Properties.Item("DefaultNamespace").Value.ToString() }; var result = modelDialog.ShowModal(); if (!result.HasValue || result.Value != true) { return; } var projectPath = project.Properties.Item("FullPath").Value.ToString(); var options = new ReverseEngineerOptions { UseFluentApiOnly = !modelDialog.UseDataAnnotations, ConnectionString = databaseInfo.DatabaseInfo.ConnectionString, ContextClassName = modelDialog.ModelName, DatabaseType = (EFCoreReverseEngineer.DatabaseType)dbType, ProjectPath = projectPath, OutputPath = modelDialog.OutputPath, ProjectRootNamespace = modelDialog.NameSpace, Tables = ptd.Tables }; var revEngResult = revEng.GenerateFiles(options); if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 2) { foreach (var filePath in revEngResult.EntityTypeFilePaths) { project.ProjectItems.AddFromFile(filePath); } } if (modelDialog.SelectedTobeGenerated == 0 || modelDialog.SelectedTobeGenerated == 1) { project.ProjectItems.AddFromFile(revEngResult.ContextFilePath); dte.ItemOperations.OpenFile(revEngResult.ContextFilePath); } packageResult = dteH.ContainsEfCoreReference(project, dbType); var missingProviderPackage = packageResult.Item1 ? null : packageResult.Item2; if (modelDialog.InstallNuGetPackage) { missingProviderPackage = null; } ReportRevEngErrors(revEngResult, missingProviderPackage); if (modelDialog.InstallNuGetPackage) { package.SetStatus("Installing EF Core provider package"); var nuGetHelper = new NuGetHelper(); await nuGetHelper.InstallPackageAsync(packageResult.Item2, project); } DataConnectionHelper.LogUsage("DatabaseCreateEfCoreModel"); } catch (Exception ex) { package.SetStatus(null); DataConnectionHelper.SendError(ex, databaseInfo.DatabaseInfo.DatabaseType, false); } }
private Dictionary <string, string> ReverseEngineerFiles(ReverseEngineerOptions options, bool useDataAnnotations) { var fileService = new InMemoryTemplateFileService(); fileService.InputFiles(ContextClassTemplate, ContextImportsTemplate, ContextDbSetsTemplate, EntityClassTemplate, EntityImportsTemplate, EntityCtorTemplate, EntityPropertiesTemplate); var dbContextTemplateService = new HbsDbContextTemplateService(fileService); var entityTypeTemplateService = new HbsEntityTypeTemplateService(fileService); ICSharpUtilities cSharpUtilities = new CSharpUtilities(); ICSharpDbContextGenerator realContextGenerator = new HbsCSharpDbContextGenerator( new SqlServerScaffoldingCodeGenerator(), new SqlServerAnnotationCodeGenerator(new AnnotationCodeGeneratorDependencies()), cSharpUtilities, new HbsDbContextTemplateService(fileService)); ICSharpDbContextGenerator contextGenerator = options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextOnly ? realContextGenerator : new NullCSharpDbContextGenerator(); ICSharpEntityTypeGenerator realEntityGenerator = new HbsCSharpEntityTypeGenerator( cSharpUtilities, new HbsEntityTypeTemplateService(fileService)); ICSharpEntityTypeGenerator entityGenerator = options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities ? realEntityGenerator : new NullCSharpEntityTypeGenerator(); IScaffoldingCodeGenerator scaffoldingGenerator = new HbsCSharpScaffoldingGenerator( fileService, dbContextTemplateService, entityTypeTemplateService, contextGenerator, entityGenerator); var modelFactory = new SqlServerDatabaseModelFactory( new DiagnosticsLogger <DbLoggerCategory.Scaffolding>( new TestSqlLoggerFactory(), new LoggingOptions(), new DiagnosticListener("Fake"))); var reverseEngineer = new ReverseEngineerScaffolder( modelFactory, new FakeScaffoldingModelFactory(new TestOperationReporter()), scaffoldingGenerator, cSharpUtilities); // Act var files = reverseEngineer.Generate( connectionString: Constants.Connections.SqlServerConnection, tables: Enumerable.Empty <string>(), schemas: Enumerable.Empty <string>(), projectPath: Constants.Parameters.ProjectPath, outputPath: null, rootNamespace: Constants.Parameters.RootNamespace, contextName: Constants.Parameters.ContextName, useDataAnnotations: useDataAnnotations, overwriteFiles: false, useDatabaseNames: false); var generatedFiles = new Dictionary <string, string>(); if (options == ReverseEngineerOptions.DbContextOnly || options == ReverseEngineerOptions.DbContextAndEntities) { var contextPath = files.ContextFile; var context = fileService.RetrieveTemplateFileContents( Path.GetDirectoryName(contextPath), Path.GetFileName(contextPath)); generatedFiles.Add(Constants.Files.DbContextFile, context); } if (options == ReverseEngineerOptions.EntitiesOnly || options == ReverseEngineerOptions.DbContextAndEntities) { var categoryPath = files.EntityTypeFiles[0]; var category = fileService.RetrieveTemplateFileContents( Path.GetDirectoryName(categoryPath), Path.GetFileName(categoryPath)); var productPath = files.EntityTypeFiles[1]; var product = fileService.RetrieveTemplateFileContents( Path.GetDirectoryName(productPath), Path.GetFileName(productPath)); generatedFiles.Add(Constants.Files.CategoryFile, category); generatedFiles.Add(Constants.Files.ProductFile, product); } return(generatedFiles); }