Skip to content

Commit

Permalink
WIP: Adds support for Using EntityTypeConfiguration files. (#2582)
Browse files Browse the repository at this point in the history
* Adds support for Using EntityTypeConfiguration files.

* Fix code smells

* Adds new use-t4-split option.  Adds example t4's configured for EntityTypeConfiguraiton usage.  adds warning if you try to use use-t4 and use-t4-split. Adds warning if you try to use use-t4 and split-dbcontext-preview.

* Fix version for EntityTypeConfiguraiton to 8.

* Fixes T800 Zip file nesting.
Adds T800 Zip File unzipping for CLI.

* PR Feedback.

Adds use-t4-split to the VS schema json.
Moves the warnings about use-t4-split + use-t4 to ReverseEngineerRunner
Fxes UseT4Split JsonPropertyOrder being the same as UseT4
Removes sample EntityTypeConfiguration now that it exists in the 800_split folder.
  • Loading branch information
jwyza-pi authored Nov 8, 2024
1 parent bb0db72 commit f52f9da
Show file tree
Hide file tree
Showing 17 changed files with 891 additions and 12 deletions.
5 changes: 5 additions & 0 deletions samples/efcpt-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@
"type": "boolean",
"title": "Customize code using T4 templates"
},
"use-t4-split": {
"type": "boolean",
"default": false,
"title": "Customize code using T4 templates including EntityTypeConfiguration.t4. This cannot be used in combination with use-t4 or split-dbcontext-preview"
},
"remove-defaultsql-from-bool-properties": {
"type": "boolean",
"title": "Remove SQL default from bool columns to avoid them being bool?"
Expand Down
8 changes: 8 additions & 0 deletions samples/efcpt-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,14 @@
false
]
},
"use-t4-split": {
"type": "boolean",
"default": false,
"title": "Customize code using T4 templates including EntityTypeConfiguration.t4. This cannot be used in combination with use-t4 or split-dbcontext-preview",
"examples": [
false
]
},
"t4-template-path": {
"type": [ "string", "null" ] ,
"default": null,
Expand Down
2 changes: 1 addition & 1 deletion src/Core/RevEng.Core.60/IReverseEngineerScaffolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace RevEng.Core
{
public interface IReverseEngineerScaffolder
{
SavedModelFiles GenerateDbContext(ReverseEngineerCommandOptions options, List<string> schemas, string outputContextDir, string modelNamespace, string contextNamespace, string projectPath, string outputPath);
SavedModelFiles GenerateDbContext(ReverseEngineerCommandOptions options, List<string> schemas, string outputContextDir, string modelNamespace, string contextNamespace, string projectPath, string outputPath, string rootNameSpace);
SavedModelFiles GenerateFunctions(ReverseEngineerCommandOptions options, List<string> schemas, ref List<string> errors, string outputContextDir, string modelNamespace, string contextNamespace, bool supportsFunctions);
SavedModelFiles GenerateStoredProcedures(ReverseEngineerCommandOptions options, List<string> schemas, ref List<string> errors, string outputContextDir, string modelNamespace, string contextNamespace, bool supportsProcedures);
}
Expand Down
43 changes: 38 additions & 5 deletions src/Core/RevEng.Core.60/ReverseEngineerRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ public static ReverseEngineerResult GenerateFiles(ReverseEngineerCommandOptions

try
{
SavedModelFiles filePaths = scaffolder!.GenerateDbContext(options, schemas, outputContextDir, modelNamespace, contextNamespace, options.ProjectPath, options.OutputPath);
SavedModelFiles filePaths = scaffolder!.GenerateDbContext(options, schemas, outputContextDir, modelNamespace, contextNamespace, options.ProjectPath, options.OutputPath, options.ProjectRootNamespace);

#if CORE70 || CORE80
if (options.UseT4)
if (options.UseT4 || options.UseT4Split)
{
foreach (var paths in GetAlternateCodeTemplatePaths(options.ProjectPath))
{
scaffolder!.GenerateDbContext(options, schemas, paths.Path, modelNamespace, contextNamespace, paths.Path, paths.OutputPath);
scaffolder!.GenerateDbContext(options, schemas, paths.Path, modelNamespace, contextNamespace, paths.Path, paths.OutputPath, options.ProjectRootNamespace);
}
}
#endif
Expand Down Expand Up @@ -139,20 +139,25 @@ public static ReverseEngineerResult GenerateFiles(ReverseEngineerCommandOptions
}

RemoveFragments(filePaths.ContextFile, options.ContextClassName, options.IncludeConnectionString, options.UseNoDefaultConstructor);
if (!options.UseHandleBars && !options.UseT4)
if (!options.UseHandleBars && !options.UseT4 && !options.UseT4Split)
{
PostProcess(filePaths.ContextFile, options.UseNullableReferences);
}

entityTypeConfigurationPaths = SplitDbContext(filePaths.ContextFile, options.UseDbContextSplitting, contextNamespace, options.UseNullableReferences, options.ContextClassName);

if (options.UseT4Split)
{
entityTypeConfigurationPaths.AddRange(MoveConfigurationFiles(filePaths.AdditionalFiles));
}
}
else if (options.Tables.Exists(t => t.ObjectType == ObjectType.Procedure)
|| options.Tables.Exists(t => t.ObjectType == ObjectType.ScalarFunction))
{
warnings.Add("Selected stored procedures/scalar functions will not be generated, as 'Entity Types only' was selected");
}

if (!options.UseHandleBars && !options.UseT4)
if (!options.UseHandleBars && !options.UseT4 && !options.UseT4Split)
{
foreach (var file in filePaths.AdditionalFiles)
{
Expand Down Expand Up @@ -193,6 +198,18 @@ public static ReverseEngineerResult GenerateFiles(ReverseEngineerCommandOptions
warnings.Add($"'use-database-names' / 'UseDatabaseNames' has been set to true, but a '{Constants.RenamingFileName}' file was also found. This prevents '{Constants.RenamingFileName}' from functioning.");
}

if (options.UseT4 && options.UseT4Split)
{
warnings.Add("Both UseT4 and UseT4Split are set to true. Only one of thse should be used, UseT4Split will be ignored.");
options.UseT4Split = false;
}

if (options.UseT4Split && options.UseDbContextSplitting)
{
warnings.Add("Both UseDbContextSplitting and UseT4Split are set to true. Only one of thse should be used, UseT4Split will be ignored.");
options.UseT4Split = false;
}

var result = new ReverseEngineerResult
{
EntityErrors = errors,
Expand Down Expand Up @@ -323,6 +340,22 @@ private static List<string> SplitDbContext(string contextFile, bool useDbContext
return DbContextSplitter.Split(contextFile, contextNamespace, supportNullable, dbContextName);
}

// If we didn't split, we might have used EntityTypeConfiguration.t4. In that case, <ModelName>Configuration.cs files were generated.
private static List<string> MoveConfigurationFiles(IList<string> files)
{
var configurationFiles = files.Where(x => x.EndsWith("Configuration.cs", StringComparison.InvariantCulture)).ToList();

var movedFiles = new List<string>();
foreach (var configurationFile in configurationFiles)
{
var newFileName = Path.Combine(Path.GetDirectoryName(configurationFile) ?? string.Empty, "Configurations", Path.GetFileName(configurationFile));
File.Move(configurationFile, newFileName, overwrite: true);
movedFiles.Add(newFileName);
}

return movedFiles;
}

private static void RemoveFragments(string contextFile, string contextName, bool includeConnectionString, bool removeDefaultConstructor)
{
if (string.IsNullOrEmpty(contextFile))
Expand Down
7 changes: 4 additions & 3 deletions src/Core/RevEng.Core.60/ReverseEngineerScaffolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ public SavedModelFiles GenerateDbContext(
string modelNamespace,
string contextNamespace,
string projectPath,
string outputPath)
string outputPath,
string rootNameSpace)
{
ArgumentNullException.ThrowIfNull(options);

Expand All @@ -77,15 +78,15 @@ public SavedModelFiles GenerateDbContext(

ContextName = code.Identifier(options.ContextClassName),
ContextDir = outputContextDir,
RootNamespace = null,
RootNamespace = rootNameSpace,
ContextNamespace = contextNamespace,
ModelNamespace = modelNamespace,
SuppressConnectionStringWarning = false,
ConnectionString = options.ConnectionString,
SuppressOnConfiguring = !options.IncludeConnectionString,
UseNullableReferenceTypes = options.UseNullableReferences,
#if CORE70 || CORE80
ProjectDir = options.UseT4 ? (options.T4TemplatePath ?? projectPath) : null,
ProjectDir = (options.UseT4 || options.UseT4Split) ? (options.T4TemplatePath ?? projectPath) : null,
#endif
};

Expand Down
4 changes: 2 additions & 2 deletions src/Core/efcpt.8/HostedServices/ScaffoldHostedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

#pragma warning disable S2589 // Boolean expressions should not be gratuitous
#pragma warning disable S2583 // Conditionally executed code should be reachable
if (commandOptions.UseT4 && Constants.Version > 6)
if ((commandOptions.UseT4 || commandOptions.UseT4Split) && Constants.Version > 6)
{
var t4Result = T4Helper.DropT4Templates(commandOptions.T4TemplatePath ?? commandOptions.ProjectPath, Constants.CodeGeneration);
var t4Result = T4Helper.DropT4Templates(commandOptions.T4TemplatePath ?? commandOptions.ProjectPath, Constants.CodeGeneration, commandOptions.UseT4Split);
if (!string.IsNullOrEmpty(t4Result))
{
DisplayService.MarkupLine(t4Result, Color.Default);
Expand Down
3 changes: 3 additions & 0 deletions src/Core/efcpt.8/efcpt.8.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
<Content Include="..\..\GUI\lib\T4_800.zip" Link="T4_800.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="..\..\GUI\lib\T4_800_Split.zip" Link="T4_800_Split.zip">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="efcpt-readme.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Expand Down
1 change: 1 addition & 0 deletions src/GUI/RevEng.Shared/Cli/CliConfigMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static ReverseEngineerCommandOptions ToCommandOptions(
UseInflector = config.CodeGeneration.UseInflector,
UseT4 = config.CodeGeneration.UseT4,
T4TemplatePath = config.CodeGeneration.T4TemplatePath != null ? PathHelper.GetAbsPath(config.CodeGeneration.T4TemplatePath, projectPath) : null,
UseT4Split = config.CodeGeneration.UseT4Split,
IncludeConnectionString = !isDacpac && config.CodeGeneration.EnableOnConfiguring,
SelectedToBeGenerated = selectedToBeGenerated,
Dacpac = isDacpac ? connectionString : null,
Expand Down
4 changes: 4 additions & 0 deletions src/GUI/RevEng.Shared/Cli/Configuration/CodeGeneration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,9 @@ public class CodeGeneration
[JsonPropertyOrder(200)]
[JsonPropertyName("use-t4")]
public bool UseT4 { get; set; }

[JsonPropertyOrder(210)]
[JsonPropertyName("use-t4-split")]
public bool UseT4Split { get; set; }
}
}
17 changes: 16 additions & 1 deletion src/GUI/RevEng.Shared/Cli/T4Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace RevEng.Common.Cli
{
public static class T4Helper
{
public static string DropT4Templates(string projectPath, CodeGenerationMode codeGenerationMode)
public static string DropT4Templates(string projectPath, CodeGenerationMode codeGenerationMode, bool useEntityTypeSplitting = false)
{
string t4Version = "703";

Expand All @@ -22,6 +22,11 @@ public static string DropT4Templates(string projectPath, CodeGenerationMode code
t4Version = "900";
}

if (useEntityTypeSplitting)
{
t4Version += "_Split";
}

var zipName = $"T4_{t4Version}.zip";

var toDir = Path.Combine(projectPath, "CodeTemplates");
Expand Down Expand Up @@ -57,6 +62,16 @@ public static string DropT4Templates(string projectPath, CodeGenerationMode code
return error;
}
}

target = Path.Combine(toDir, "EFCore", "EntityTypeConfiguration.t4");
if (File.Exists(target))
{
var content = File.ReadAllText(target, Encoding.UTF8);
if (content.IndexOf(check, StringComparison.OrdinalIgnoreCase) == -1)
{
return error;
}
}
}

return string.Empty;
Expand Down
1 change: 1 addition & 0 deletions src/GUI/RevEng.Shared/ReverseEngineerCommandOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class ReverseEngineerCommandOptions
public bool UseHandleBars { get; set; }
public bool UseT4 { get; set; }
public string T4TemplatePath { get; set; }
public bool UseT4Split { get; set; }
public int SelectedHandlebarsLanguage { get; set; }
public bool IncludeConnectionString { get; set; }
public int SelectedToBeGenerated { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/GUI/RevEng.Shared/ReverseEngineerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class ReverseEngineerOptions
public List<string> UncountableWords { get; set; }
public bool UseHandleBars { get; set; }
public bool UseT4 { get; set; }
public bool UseT4Split { get; set; }
public int SelectedHandlebarsLanguage { get; set; } = 2;
public bool IncludeConnectionString { get; set; }
public int SelectedToBeGenerated { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public static async Task<ReverseEngineerResult> LaunchExternalRunnerAsync(Revers
UseHandleBars = options.UseHandleBars,
UseT4 = options.UseT4,
T4TemplatePath = options.T4TemplatePath != null ? PathHelper.GetAbsPath(options.T4TemplatePath, options.ProjectPath) : null,
UseT4Split = options.UseT4Split,
UseInflector = options.UseInflector,
UseLegacyPluralizer = options.UseLegacyPluralizer,
UncountableWords = options.UncountableWords,
Expand Down
Binary file added src/GUI/lib/T4_800_Split.zip
Binary file not shown.
Loading

0 comments on commit f52f9da

Please sign in to comment.