From 5a759d5f61d2e28fc651f7059ce8b8bc0fe7ee3a Mon Sep 17 00:00:00 2001
From: Daniele Maltese <17677294+ilmalte@users.noreply.github.com>
Date: Wed, 18 May 2022 20:50:29 +0200
Subject: [PATCH] Capitalize database name (#27966)
When scaffolding from a database the database name is modified in order to respect .NET conventions
#Fixes 27886
---
.../Internal/CandidateNamingService.cs | 8 ++++-
.../Internal/ICandidateNamingService.cs | 9 ++++++
.../RelationalScaffoldingModelFactory.cs | 5 +++-
.../RelationalScaffoldingModelFactoryTest.cs | 29 +++++++++++++++++++
4 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs b/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs
index 5cb31203222..5570a0aaa02 100644
--- a/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/CandidateNamingService.cs
@@ -65,7 +65,13 @@ public virtual string GetPrincipalEndCandidateNavigationPropertyName(
: foreignKey.DeclaringEntityType.ShortName();
}
- private static string GenerateCandidateIdentifier(string originalIdentifier)
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ public virtual string GenerateCandidateIdentifier(string originalIdentifier)
{
var candidateStringBuilder = new StringBuilder();
var previousLetterCharInWordIsLowerCase = false;
diff --git a/src/EFCore.Design/Scaffolding/Internal/ICandidateNamingService.cs b/src/EFCore.Design/Scaffolding/Internal/ICandidateNamingService.cs
index 45bf5e1c8c0..16a22718321 100644
--- a/src/EFCore.Design/Scaffolding/Internal/ICandidateNamingService.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/ICandidateNamingService.cs
@@ -29,6 +29,15 @@ public interface ICandidateNamingService
///
string GenerateCandidateIdentifier(DatabaseColumn originalColumn);
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ string GenerateCandidateIdentifier(string databaseName);
+
+
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
diff --git a/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs b/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs
index 839dfbcf7c4..2ce3b6ab19e 100644
--- a/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs
+++ b/src/EFCore.Design/Scaffolding/Internal/RelationalScaffoldingModelFactory.cs
@@ -166,7 +166,10 @@ protected virtual ModelBuilder VisitDatabaseModel(ModelBuilder modelBuilder, Dat
if (!string.IsNullOrEmpty(databaseModel.DatabaseName))
{
- modelBuilder.Model.SetDatabaseName(databaseModel.DatabaseName);
+ modelBuilder.Model.SetDatabaseName(
+ !_options.UseDatabaseNames && !string.IsNullOrEmpty(databaseModel.DatabaseName)
+ ? _candidateNamingService.GenerateCandidateIdentifier(databaseModel.DatabaseName)
+ : databaseModel.DatabaseName);
}
if (!string.IsNullOrEmpty(databaseModel.Collation))
diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/RelationalScaffoldingModelFactoryTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/RelationalScaffoldingModelFactoryTest.cs
index 6cf32d7cebf..2741df760e7 100644
--- a/test/EFCore.Design.Tests/Scaffolding/Internal/RelationalScaffoldingModelFactoryTest.cs
+++ b/test/EFCore.Design.Tests/Scaffolding/Internal/RelationalScaffoldingModelFactoryTest.cs
@@ -50,6 +50,14 @@ public RelationalScaffoldingModelFactoryTest()
_reporter.Clear();
}
+ [ConditionalFact]
+ public void Capitalize_DatabaseName()
+ {
+ var database = new DatabaseModel { DatabaseName = "northwind" };
+ var model = _factory.Create(database, new ModelReverseEngineerOptions { UseDatabaseNames = false });
+ Assert.Equal("Northwind", model.GetDatabaseName());
+ }
+
[ConditionalFact]
public void Creates_entity_types()
{
@@ -131,6 +139,27 @@ public void Creates_entity_types_case_insensitive()
Assert.Equal(2, model.GetEntityTypes().Select(et => et.Name).Distinct(StringComparer.OrdinalIgnoreCase).Count());
}
+ [ConditionalTheory]
+ [InlineData("PascalCase")]
+ [InlineData("camelCase")]
+ [InlineData("snake-case")]
+ [InlineData("MixedCASE")]
+ [InlineData("separated_by_underscores")]
+ [InlineData("PascalCase_withUnderscore")]
+ [InlineData("ALL_CAPS")]
+ [InlineData("numbers0Dont1Affect23Upper45Case678To9LowerCase10Boundary999")]
+ [InlineData("We1!*~&%rdCh@r^act()0rs")]
+ public void Get_DatabaseName(string expectedValue)
+ {
+ var options = new ModelReverseEngineerOptions { UseDatabaseNames = true };
+
+ var database = new DatabaseModel { DatabaseName = expectedValue };
+ var model = _factory.Create(database, options);
+ Assert.Equal(expectedValue, model.GetDatabaseName());
+
+ }
+
+
[ConditionalFact]
public void Loads_column_types()
{