diff --git a/src/EFCore.Design/EFCore.Design.csproj b/src/EFCore.Design/EFCore.Design.csproj
index f1fd0f511d3..7f724b52bde 100644
--- a/src/EFCore.Design/EFCore.Design.csproj
+++ b/src/EFCore.Design/EFCore.Design.csproj
@@ -62,7 +62,7 @@
-
+
diff --git a/src/EFCore.Design/Scaffolding/Internal/TextTemplatingModelGenerator.cs b/src/EFCore.Design/Scaffolding/Internal/TextTemplatingModelGenerator.cs
index fba4c63fe0f..9acf85f2f16 100644
--- a/src/EFCore.Design/Scaffolding/Internal/TextTemplatingModelGenerator.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/TextTemplatingModelGenerator.cs
@@ -2,9 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.CodeDom.Compiler;
+using System.Globalization;
using System.Text;
using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Internal;
+using Microsoft.VisualStudio.TextTemplating;
using Mono.TextTemplating;
namespace Microsoft.EntityFrameworkCore.Scaffolding.Internal;
@@ -102,12 +104,18 @@ public override ScaffoldedModel GenerateModel(IModel model, ModelCodeGenerationO
};
var contextTemplate = Path.Combine(options.ProjectDir!, TemplatesDirectory, DbContextTemplate);
- string generatedCode;
+ string? generatedCode = null;
if (File.Exists(contextTemplate))
{
host.TemplateFile = contextTemplate;
- generatedCode = Engine.ProcessTemplate(File.ReadAllText(contextTemplate), host);
+ var compiledTemplate = Engine.CompileTemplateAsync(File.ReadAllText(contextTemplate), host, new()).GetAwaiter().GetResult();
+
+ if (compiledTemplate != null)
+ {
+ generatedCode = ProcessTemplate(compiledTemplate, host);
+ }
+
CheckEncoding(host.OutputEncoding);
HandleErrors(host);
}
@@ -142,7 +150,7 @@ public override ScaffoldedModel GenerateModel(IModel model, ModelCodeGenerationO
Path = options.ContextDir != null
? Path.Combine(options.ContextDir, dbContextFileName)
: dbContextFileName,
- Code = generatedCode
+ Code = generatedCode!
}
};
@@ -165,12 +173,16 @@ public override ScaffoldedModel GenerateModel(IModel model, ModelCodeGenerationO
if (compiledEntityTypeTemplate is null)
{
- compiledEntityTypeTemplate = Engine.CompileTemplate(File.ReadAllText(entityTypeTemplate), host);
+ compiledEntityTypeTemplate = Engine.CompileTemplateAsync(File.ReadAllText(entityTypeTemplate), host, new()).GetAwaiter().GetResult();;
entityTypeExtension = host.Extension;
CheckEncoding(host.OutputEncoding);
}
- generatedCode = compiledEntityTypeTemplate.Process();
+ if (compiledEntityTypeTemplate != null)
+ {
+ generatedCode = ProcessTemplate(compiledEntityTypeTemplate, host);
+ }
+
HandleErrors(host);
if (string.IsNullOrWhiteSpace(generatedCode))
@@ -208,12 +220,16 @@ public override ScaffoldedModel GenerateModel(IModel model, ModelCodeGenerationO
if (compiledConfigurationTemplate is null)
{
- compiledConfigurationTemplate = Engine.CompileTemplate(File.ReadAllText(configurationTemplate), host);
+ compiledConfigurationTemplate = Engine.CompileTemplateAsync(File.ReadAllText(configurationTemplate), host, new()).GetAwaiter().GetResult();;
configurationExtension = host.Extension;
CheckEncoding(host.OutputEncoding);
}
- generatedCode = compiledConfigurationTemplate.Process();
+ if (compiledConfigurationTemplate != null)
+ {
+ generatedCode = ProcessTemplate(compiledConfigurationTemplate, host);
+ }
+
HandleErrors(host);
if (string.IsNullOrWhiteSpace(generatedCode))
@@ -241,6 +257,61 @@ public override ScaffoldedModel GenerateModel(IModel model, ModelCodeGenerationO
return resultingFiles;
}
+ private static string ProcessTemplate(CompiledTemplate compiledTemplate, TextTemplatingEngineHost host)
+ {
+ var templateAssemblyData = GetField(compiledTemplate, "templateAssemblyData")!;
+ var templateClassFullName = (string)GetField(compiledTemplate, "templateClassFullName")!;
+ var culture = GetField(compiledTemplate, "culture");
+ var assemblyBytes = (byte[])templateAssemblyData.GetType().GetProperty("Assembly")!.GetValue(templateAssemblyData)!;
+
+ var assembly = Assembly.Load(assemblyBytes);
+ var transformType = assembly.GetType(templateClassFullName)!;
+ var textTransformation = Activator.CreateInstance(transformType);
+
+ var hostProp = transformType.GetProperty("Host", typeof(ITextTemplatingEngineHost));
+ if (hostProp != null)
+ {
+ hostProp.SetValue(textTransformation, host, null);
+ }
+
+ var sessionProp = transformType.GetProperty("Session", typeof(IDictionary));
+ if (sessionProp != null)
+ {
+ sessionProp.SetValue(textTransformation, host.Session, null);
+ }
+
+ var errorProp = transformType.GetProperty("Errors", BindingFlags.Instance | BindingFlags.NonPublic)!;
+ var errorMethod = transformType.GetMethod("Error", new[] { typeof(string) })!;
+
+ var errors = (CompilerErrorCollection)errorProp.GetValue(textTransformation, null)!;
+ errors.Clear();
+
+ ToStringHelper.FormatProvider = culture != null ? (IFormatProvider)culture : CultureInfo.InvariantCulture;
+
+ string? output = null;
+
+ var initMethod = transformType.GetMethod("Initialize")!;
+ var transformMethod = transformType.GetMethod("TransformText")!;
+
+ try
+ {
+ initMethod.Invoke(textTransformation, null);
+ output = (string?)transformMethod.Invoke(textTransformation, null);
+ }
+ catch (Exception ex)
+ {
+ errorMethod.Invoke(textTransformation, new object[] { "Error running transform: " + ex });
+ }
+
+ host.LogErrors(errors);
+ return output!;
+
+ static object? GetField(CompiledTemplate compiledTemplate, string fieldName)
+ => compiledTemplate.GetType()
+ .GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic)!
+ .GetValue(compiledTemplate);
+ }
+
private void CheckEncoding(Encoding outputEncoding)
{
if (outputEncoding != Encoding.UTF8)
diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs
index 73e294a56ce..10c67399449 100644
--- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs
+++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpDbContextGeneratorTest.cs
@@ -18,8 +18,10 @@ public CSharpDbContextGeneratorTest(ModelCodeGeneratorTestFixture fixture, ITest
{
}
- [ConditionalFact]
- public Task Empty_model()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Empty_model(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => { },
new ModelCodeGenerationOptions(),
@@ -60,10 +62,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
Assert.Empty(code.AdditionalFiles);
},
- model => Assert.Empty(model.GetEntityTypes()));
+ model => Assert.Empty(model.GetEntityTypes()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task SuppressConnectionStringWarning_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task SuppressConnectionStringWarning_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => { },
new ModelCodeGenerationOptions { SuppressConnectionStringWarning = true },
@@ -103,10 +108,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
Assert.Empty(code.AdditionalFiles);
},
- model => Assert.Empty(model.GetEntityTypes()));
+ model => Assert.Empty(model.GetEntityTypes()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task SuppressOnConfiguring_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task SuppressOnConfiguring_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => { },
new ModelCodeGenerationOptions { SuppressOnConfiguring = true },
@@ -141,8 +149,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
},
null);
- [ConditionalFact]
- public Task DbSets_without_nrt()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task DbSets_without_nrt(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity"),
new ModelCodeGenerationOptions
@@ -156,10 +166,13 @@ public Task DbSets_without_nrt()
Assert.Contains("DbSet Entity { get; set; }", code.ContextFile.Code);
Assert.DoesNotContain("DbSet Entity { get; set; } = null!;", code.ContextFile.Code);
},
- null);
+ null,
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task DbSets_with_nrt()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task DbSets_with_nrt(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity"),
new ModelCodeGenerationOptions
@@ -173,7 +186,8 @@ public Task DbSets_with_nrt()
Assert.Contains("DbSet Entity { get; set; }", code.ContextFile.Code);
Assert.DoesNotContain("DbSet Entity { get; set; } = null!;", code.ContextFile.Code);
},
- null);
+ null,
+ useTemplateGenerator: useTemplateGenerator);
[ConditionalFact]
public void Required_options_to_GenerateModel_are_not_null()
@@ -230,8 +244,10 @@ public void Plugins_work()
scaffoldedModel.ContextFile.Code);
}
- [ConditionalFact]
- public Task IsRequired_is_generated_for_ref_property_without_nrt()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task IsRequired_is_generated_for_ref_property_without_nrt(bool useTemplateGenerator)
=> TestAsync(
modelBuilder =>
{
@@ -259,10 +275,13 @@ public Task IsRequired_is_generated_for_ref_property_without_nrt()
Assert.True(entityType.GetProperty("NonRequiredString").IsNullable);
Assert.False(entityType.GetProperty("RequiredInt").IsNullable);
Assert.True(entityType.GetProperty("NonRequiredInt").IsNullable);
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task IsRequired_is_not_generated_for_ref_property_with_nrt()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task IsRequired_is_not_generated_for_ref_property_with_nrt(bool useTemplateGenerator)
=> TestAsync(
modelBuilder =>
{
@@ -290,10 +309,13 @@ public Task IsRequired_is_not_generated_for_ref_property_with_nrt()
Assert.True(entityType.GetProperty("NonRequiredString").IsNullable);
Assert.False(entityType.GetProperty("RequiredInt").IsNullable);
Assert.True(entityType.GetProperty("NonRequiredInt").IsNullable);
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Comments_use_fluent_api()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Comments_use_fluent_api(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity(
"Entity",
@@ -309,10 +331,13 @@ public Task Comments_use_fluent_api()
code.ContextFile.Code),
model => Assert.Equal(
"An int property",
- model.FindEntityType("TestNamespace.Entity").GetProperty("Property").GetComment()));
+ model.FindEntityType("TestNamespace.Entity").GetProperty("Property").GetComment()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Entity_comments_use_fluent_api()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Entity_comments_use_fluent_api(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity(
"Entity",
@@ -326,10 +351,13 @@ public Task Entity_comments_use_fluent_api()
code.ContextFile.Code),
model => Assert.Equal(
"An entity comment",
- model.FindEntityType("TestNamespace.Entity").GetComment()));
+ model.FindEntityType("TestNamespace.Entity").GetComment()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Views_work()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Views_work(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Vista").ToView("Vista"),
new ModelCodeGenerationOptions { UseDataAnnotations = true },
@@ -343,10 +371,13 @@ public Task Views_work()
Assert.Null(entityType.GetViewSchema());
Assert.Null(entityType.GetTableName());
Assert.Null(entityType.GetSchema());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task ModelInDifferentNamespaceDbContext_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ModelInDifferentNamespaceDbContext_works(bool useTemplateGenerator)
{
var modelGenerationOptions = new ModelCodeGenerationOptions
{
@@ -356,30 +387,34 @@ public Task ModelInDifferentNamespaceDbContext_works()
const string entityInAnotherNamespaceTypeName = "EntityInAnotherNamespace";
return TestAsync(
- modelBuilder => modelBuilder.Entity(entityInAnotherNamespaceTypeName)
- , modelGenerationOptions
- , code => Assert.Contains(string.Concat("using ", modelGenerationOptions.ModelNamespace, ";"), code.ContextFile.Code)
- , model => Assert.NotNull(model.FindEntityType(string.Concat(modelGenerationOptions.ModelNamespace, ".", entityInAnotherNamespaceTypeName)))
- );
+ modelBuilder => modelBuilder.Entity(entityInAnotherNamespaceTypeName),
+ modelGenerationOptions,
+ code => Assert.Contains(string.Concat("using ", modelGenerationOptions.ModelNamespace, ";"), code.ContextFile.Code),
+ model => Assert.NotNull(model.FindEntityType(string.Concat(modelGenerationOptions.ModelNamespace, ".", entityInAnotherNamespaceTypeName))),
+ useTemplateGenerator: useTemplateGenerator);
}
- [ConditionalFact]
- public Task ModelSameNamespaceDbContext_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ModelSameNamespaceDbContext_works(bool useTemplateGenerator)
{
var modelGenerationOptions = new ModelCodeGenerationOptions { ContextNamespace = "TestNamespace" };
const string entityInAnotherNamespaceTypeName = "EntityInAnotherNamespace";
return TestAsync(
- modelBuilder => modelBuilder.Entity(entityInAnotherNamespaceTypeName)
- , modelGenerationOptions
- , code => Assert.DoesNotContain(string.Concat("using ", modelGenerationOptions.ModelNamespace, ";"), code.ContextFile.Code)
- , model => Assert.NotNull(model.FindEntityType(string.Concat(modelGenerationOptions.ModelNamespace, ".", entityInAnotherNamespaceTypeName)))
- );
+ modelBuilder => modelBuilder.Entity(entityInAnotherNamespaceTypeName),
+ modelGenerationOptions,
+ code => Assert.DoesNotContain(string.Concat("using ", modelGenerationOptions.ModelNamespace, ";"), code.ContextFile.Code),
+ model => Assert.NotNull(model.FindEntityType(string.Concat(modelGenerationOptions.ModelNamespace, ".", entityInAnotherNamespaceTypeName))),
+ useTemplateGenerator: useTemplateGenerator);
}
- [ConditionalFact]
- public Task ValueGenerated_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ValueGenerated_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity(
"Entity",
@@ -408,10 +443,13 @@ public Task ValueGenerated_works()
Assert.True(entity.GetProperty("ConcurrencyToken").IsConcurrencyToken);
Assert.Equal(ValueGenerated.OnUpdate, entity.GetProperty("ValueGeneratedOnUpdate").ValueGenerated);
Assert.Equal(ValueGenerated.Never, entity.GetProperty("ValueGeneratedNever").ValueGenerated);
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task HasPrecision_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task HasPrecision_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity(
"Entity",
@@ -433,10 +471,13 @@ public Task HasPrecision_works()
Assert.Null(entity.GetProperty("HasPrecision").GetScale());
Assert.Equal(14, entity.GetProperty("HasPrecisionAndScale").GetPrecision());
Assert.Equal(7, entity.GetProperty("HasPrecisionAndScale").GetScale());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Collation_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Collation_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("UseCollation").UseCollation("Some Collation"),
new ModelCodeGenerationOptions(),
@@ -445,10 +486,13 @@ public Task Collation_works()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.Equal("Some Collation", entity.GetProperty("UseCollation").GetCollation());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task ComputedColumnSql_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ComputedColumnSql_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("ComputedColumn").HasComputedColumnSql("1 + 2"),
new ModelCodeGenerationOptions(),
@@ -457,10 +501,13 @@ public Task ComputedColumnSql_works()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.Equal("1 + 2", entity.GetProperty("ComputedColumn").GetComputedColumnSql());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Column_with_default_value_only_uses_default_value()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Column_with_default_value_only_uses_default_value(bool useTemplateGenerator)
=> TestAsync(
serviceProvider => serviceProvider.GetService().Create(
BuildModelWithColumn("nvarchar(max)", null, "Hot"), new ModelReverseEngineerOptions()),
@@ -471,10 +518,13 @@ public Task Column_with_default_value_only_uses_default_value()
var property = model.FindEntityType("TestNamespace.Table")!.GetProperty("Column");
Assert.Equal("Hot", property.GetDefaultValue());
Assert.Null(property.FindAnnotation(RelationalAnnotationNames.DefaultValueSql));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Column_with_default_value_sql_only_uses_default_value_sql()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Column_with_default_value_sql_only_uses_default_value_sql(bool useTemplateGenerator)
=> TestAsync(
serviceProvider => serviceProvider.GetService().Create(
BuildModelWithColumn("nvarchar(max)", "('Hot')", null), new ModelReverseEngineerOptions()),
@@ -485,10 +535,13 @@ public Task Column_with_default_value_sql_only_uses_default_value_sql()
var property = model.FindEntityType("TestNamespace.Table")!.GetProperty("Column");
Assert.Equal("('Hot')", property.GetDefaultValueSql());
Assert.Null(property.FindAnnotation(RelationalAnnotationNames.DefaultValue));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Column_with_default_value_sql_and_default_value_uses_default_value()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Column_with_default_value_sql_and_default_value_uses_default_value(bool useTemplateGenerator)
=> TestAsync(
serviceProvider => serviceProvider.GetService().Create(
BuildModelWithColumn("nvarchar(max)", "('Hot')", "Hot"), new ModelReverseEngineerOptions()),
@@ -499,10 +552,13 @@ public Task Column_with_default_value_sql_and_default_value_uses_default_value()
var property = model.FindEntityType("TestNamespace.Table")!.GetProperty("Column");
Assert.Equal("Hot", property.GetDefaultValue());
Assert.Null(property.FindAnnotation(RelationalAnnotationNames.DefaultValueSql));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Column_with_default_value_sql_and_default_value_where_value_is_CLR_default_uses_neither()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Column_with_default_value_sql_and_default_value_where_value_is_CLR_default_uses_neither(bool useTemplateGenerator)
=> TestAsync(
serviceProvider => serviceProvider.GetService().Create(
BuildModelWithColumn("int", "((0))", 0), new ModelReverseEngineerOptions()),
@@ -513,10 +569,13 @@ public Task Column_with_default_value_sql_and_default_value_where_value_is_CLR_d
var property = model.FindEntityType("TestNamespace.Table")!.GetProperty("Column");
Assert.Null(property.FindAnnotation(RelationalAnnotationNames.DefaultValue));
Assert.Null(property.FindAnnotation(RelationalAnnotationNames.DefaultValueSql));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task IsUnicode_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task IsUnicode_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder =>
{
@@ -534,10 +593,13 @@ public Task IsUnicode_works()
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.True(entity.GetProperty("UnicodeColumn").IsUnicode());
Assert.False(entity.GetProperty("NonUnicodeColumn").IsUnicode());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task ComputedColumnSql_works_stored()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ComputedColumnSql_works_stored(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("ComputedColumn")
.HasComputedColumnSql("1 + 2", stored: true),
@@ -547,10 +609,13 @@ public Task ComputedColumnSql_works_stored()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.True(entity.GetProperty("ComputedColumn").GetIsStored());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task ComputedColumnSql_works_unspecified()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ComputedColumnSql_works_unspecified(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("ComputedColumn").HasComputedColumnSql(),
new ModelCodeGenerationOptions(),
@@ -559,10 +624,13 @@ public Task ComputedColumnSql_works_unspecified()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.Empty(entity.GetProperty("ComputedColumn").GetComputedColumnSql());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task DefaultValue_works_unspecified()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task DefaultValue_works_unspecified(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("DefaultedColumn").HasDefaultValue(),
new ModelCodeGenerationOptions(),
@@ -571,10 +639,13 @@ public Task DefaultValue_works_unspecified()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.Equal(DBNull.Value, entity.GetProperty("DefaultedColumn").GetDefaultValue());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task DefaultValueSql_works_unspecified()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task DefaultValueSql_works_unspecified(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("DefaultedColumn").HasDefaultValueSql(),
new ModelCodeGenerationOptions(),
@@ -583,10 +654,13 @@ public Task DefaultValueSql_works_unspecified()
{
var entity = model.FindEntityType("TestNamespace.Entity");
Assert.Empty(entity.GetProperty("DefaultedColumn").GetDefaultValueSql());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Entity_with_indexes_and_use_data_annotations_false_always_generates_fluent_API()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Entity_with_indexes_and_use_data_annotations_false_always_generates_fluent_API(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -655,10 +729,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
code.ContextFile);
},
model =>
- Assert.Equal(2, model.FindEntityType("TestNamespace.EntityWithIndexes").GetIndexes().Count()));
+ Assert.Equal(2, model.FindEntityType("TestNamespace.EntityWithIndexes").GetIndexes().Count()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Entity_with_indexes_and_use_data_annotations_true_generates_fluent_API_only_for_indexes_with_annotations()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Entity_with_indexes_and_use_data_annotations_true_generates_fluent_API_only_for_indexes_with_annotations(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -723,10 +800,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
code.ContextFile);
},
model =>
- Assert.Equal(2, model.FindEntityType("TestNamespace.EntityWithIndexes").GetIndexes().Count()));
+ Assert.Equal(2, model.FindEntityType("TestNamespace.EntityWithIndexes").GetIndexes().Count()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Indexes_with_descending()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Indexes_with_descending(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -818,10 +898,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
var mixedIndex = Assert.Single(entityType.GetIndexes(), i => i.Name == "IX_mixed");
Assert.Equal(new[] { false, true, false }, mixedIndex.IsDescending);
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Entity_lambda_uses_correct_identifiers()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Entity_lambda_uses_correct_identifiers(bool useTemplateGenerator)
=> TestAsync(
modelBuilder =>
{
@@ -898,10 +981,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
""",
code.ContextFile);
},
- model => { });
+ model => { },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Column_type_is_not_scaffolded_as_annotation()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Column_type_is_not_scaffolded_as_annotation(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -957,10 +1043,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
code.ContextFile);
},
model =>
- Assert.Equal("date", model.FindEntityType("TestNamespace.Employee").GetProperty("HireDate").GetConfiguredColumnType()));
+ Assert.Equal("date", model.FindEntityType("TestNamespace.Employee").GetProperty("HireDate").GetConfiguredColumnType()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Is_fixed_length_annotation_should_be_scaffolded_without_optional_parameter()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Is_fixed_length_annotation_should_be_scaffolded_without_optional_parameter(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -973,10 +1062,13 @@ public Task Is_fixed_length_annotation_should_be_scaffolded_without_optional_par
new ModelCodeGenerationOptions { UseDataAnnotations = false },
code => Assert.Contains(".IsFixedLength()", code.ContextFile.Code),
model =>
- Assert.Equal(true, model.FindEntityType("TestNamespace.Employee").GetProperty("Name").IsFixedLength()));
+ Assert.Equal(true, model.FindEntityType("TestNamespace.Employee").GetProperty("Name").IsFixedLength()),
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Global_namespace_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Global_namespace_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("MyEntity"),
new ModelCodeGenerationOptions { ModelNamespace = string.Empty },
@@ -1025,10 +1117,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
model =>
{
Assert.NotNull(model.FindEntityType("MyEntity"));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Global_namespace_works_just_context()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Global_namespace_works_just_context(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("MyEntity"),
new ModelCodeGenerationOptions { ModelNamespace = "TestNamespace", ContextNamespace = string.Empty },
@@ -1041,10 +1136,13 @@ public Task Global_namespace_works_just_context()
model =>
{
Assert.NotNull(model.FindEntityType("TestNamespace.MyEntity"));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Global_namespace_works_just_model()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Global_namespace_works_just_model(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("MyEntity"),
new ModelCodeGenerationOptions { ModelNamespace = string.Empty, ContextNamespace = "TestNamespace" },
@@ -1056,10 +1154,13 @@ public Task Global_namespace_works_just_model()
model =>
{
Assert.NotNull(model.FindEntityType("MyEntity"));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Fluent_calls_in_custom_namespaces_work()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Fluent_calls_in_custom_namespaces_work(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => TestModelBuilderExtensions.TestFluentApiCall(modelBuilder),
new ModelCodeGenerationOptions { SuppressOnConfiguring = true },
@@ -1096,7 +1197,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
Assert.Empty(code.AdditionalFiles);
},
model => Assert.Empty(model.GetEntityTypes()),
- skipBuild: true);
+ skipBuild: true,
+ useTemplateGenerator: useTemplateGenerator);
[ConditionalFact]
public async Task Temporal_table_works()
@@ -1171,8 +1273,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
// TODO
}))).Message);
- [ConditionalFact]
- public Task Sequences_work()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Sequences_work(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.HasSequence("EvenNumbers", "dbo")
.StartsAt(2)
@@ -1202,10 +1306,13 @@ public Task Sequences_work()
Assert.Equal(2, sequence.MinValue);
Assert.Equal(100, sequence.MaxValue);
Assert.True(sequence.IsCyclic);
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task Trigger_works()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task Trigger_works(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder
.Entity(
@@ -1278,10 +1385,13 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
triggers,
t => Assert.Equal("Trigger1", t.GetDatabaseName()),
t => Assert.Equal("Trigger2", t.GetDatabaseName()));
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
- [ConditionalFact]
- public Task ValueGenerationStrategy_works_when_none()
+ [ConditionalTheory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public Task ValueGenerationStrategy_works_when_none(bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity(
"Channel",
@@ -1339,12 +1449,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
var entityType = Assert.Single(model.GetEntityTypes());
var property = Assert.Single(entityType.GetProperties());
Assert.Equal(SqlServerValueGenerationStrategy.None, property.GetValueGenerationStrategy());
- });
+ },
+ useTemplateGenerator: useTemplateGenerator);
[ConditionalTheory]
- [InlineData(false)]
- [InlineData(true)]
- public Task ColumnOrder_is_ignored(bool useDataAnnotations)
+ [InlineData(false, false)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ public Task ColumnOrder_is_ignored(bool useDataAnnotations, bool useTemplateGenerator)
=> TestAsync(
modelBuilder => modelBuilder.Entity("Entity").Property("Property").HasColumnOrder(1),
new ModelCodeGenerationOptions { UseDataAnnotations = useDataAnnotations },
diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs
index ae1cc54c2d0..62b739eac48 100644
--- a/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs
+++ b/test/EFCore.Design.Tests/Scaffolding/Internal/ModelCodeGeneratorTestBase.cs
@@ -24,7 +24,8 @@ protected Task TestAsync(
ModelCodeGenerationOptions options,
Action assertScaffold,
Action assertModel,
- bool skipBuild = false)
+ bool skipBuild = false,
+ bool useTemplateGenerator = true)
{
var designServices = new ServiceCollection();
AddModelServices(designServices);
@@ -39,7 +40,7 @@ protected Task TestAsync(
var serviceProvider = services.BuildServiceProvider(validateScopes: true);
- return TestAsync(serviceProvider, model, options, assertScaffold, assertModel, skipBuild);
+ return TestAsync(serviceProvider, model, options, assertScaffold, assertModel, skipBuild, useTemplateGenerator);
}
protected Task TestAsync(
@@ -47,7 +48,8 @@ protected Task TestAsync(
ModelCodeGenerationOptions options,
Action assertScaffold,
Action assertModel,
- bool skipBuild = false)
+ bool skipBuild = false,
+ bool useTemplateGenerator = true)
{
var designServices = new ServiceCollection();
AddModelServices(designServices);
@@ -56,7 +58,7 @@ protected Task TestAsync(
var serviceProvider = services.BuildServiceProvider(validateScopes: true);
var model = buildModel(serviceProvider);
- return TestAsync(serviceProvider, model, options, assertScaffold, assertModel, skipBuild);
+ return TestAsync(serviceProvider, model, options, assertScaffold, assertModel, skipBuild, useTemplateGenerator);
}
protected async Task TestAsync(
@@ -65,12 +67,14 @@ protected async Task TestAsync(
ModelCodeGenerationOptions options,
Action assertScaffold,
Action assertModel,
- bool skipBuild = false)
+ bool skipBuild = false,
+ bool useTemplateGenerator = true)
{
var generators = serviceProvider.GetServices();
- var generator = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
+ var generator =
+ RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
- || Random.Shared.Next() % 12 != 0
+ || !useTemplateGenerator
? generators.Last(g => g is CSharpModelGenerator)
: generators.Last(g => g is TextTemplatingModelGenerator);
diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/TextTemplatingEngineHostTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/TextTemplatingEngineHostTest.cs
index 1fd71e38ffc..5b58c44d932 100644
--- a/test/EFCore.Design.Tests/Scaffolding/Internal/TextTemplatingEngineHostTest.cs
+++ b/test/EFCore.Design.Tests/Scaffolding/Internal/TextTemplatingEngineHostTest.cs
@@ -22,9 +22,9 @@ public void Service_works()
.AddSingleton("Hello, Services!")
.BuildServiceProvider());
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#@ template hostSpecific=""true"" #><#= ((IServiceProvider)Host).GetService(typeof(string)) #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal("Hello, Services!", result);
@@ -35,9 +35,9 @@ public void Session_works()
{
var host = new TextTemplatingEngineHost { Session = new TextTemplatingSession { ["Value"] = "Hello, Session!" } };
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#= Session[""Value""] #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal("Hello, Session!", result);
@@ -48,9 +48,9 @@ public void Session_works_with_parameter()
{
var host = new TextTemplatingEngineHost { Session = new TextTemplatingSession { ["Value"] = "Hello, Session!" } };
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#@ parameter name=""Value"" type=""System.String"" #><#= Value #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal("Hello, Session!", result);
@@ -66,9 +66,9 @@ public void Include_works()
var host = new TextTemplatingEngineHost { TemplateFile = Path.Combine(dir, "test.tt") };
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#@ include file=""test.ttinclude"" #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal("Hello, Include!", result);
@@ -79,9 +79,9 @@ public void Error_works()
{
var host = new TextTemplatingEngineHost();
- _engine.ProcessTemplate(
+ _engine.ProcessTemplateAsync(
@"<# Error(""Hello, Error!""); #>",
- host);
+ host).GetAwaiter().GetResult();;
var error = Assert.Single(host.Errors.Cast());
Assert.Equal("Hello, Error!", error.ErrorText);
@@ -93,9 +93,9 @@ public void Directive_throws_when_processor_unknown()
var host = new TextTemplatingEngineHost();
var ex = Assert.Throws(
- () => _engine.ProcessTemplate(
+ () => _engine.ProcessTemplateAsync(
@"<#@ test processor=""TestDirectiveProcessor"" #>",
- host));
+ host).GetAwaiter().GetResult());
Assert.Equal(DesignStrings.UnknownDirectiveProcessor("TestDirectiveProcessor"), ex.Message);
}
@@ -107,9 +107,9 @@ public void ResolvePath_work()
var host = new TextTemplatingEngineHost { TemplateFile = Path.Combine(dir, "test.tt") };
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#@ template hostSpecific=""true"" #><#= Host.ResolvePath(""data.json"") #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal(Path.Combine(dir, "data.json"), result);
@@ -120,9 +120,9 @@ public void Output_works()
{
var host = new TextTemplatingEngineHost();
- _engine.ProcessTemplate(
+ _engine.ProcessTemplateAsync(
@"<#@ output extension="".txt"" encoding=""us-ascii"" #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal(".txt", host.Extension);
@@ -134,9 +134,9 @@ public void Assembly_works()
{
var host = new TextTemplatingEngineHost();
- var result = _engine.ProcessTemplate(
+ var result = _engine.ProcessTemplateAsync(
@"<#@ assembly name=""Microsoft.EntityFrameworkCore"" #><#= nameof(Microsoft.EntityFrameworkCore.DbContext) #>",
- host);
+ host).GetAwaiter().GetResult();;
Assert.Empty(host.Errors);
Assert.Equal("DbContext", result);