Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default to using Humanizer.Core as reverse engineeer pluralizer #20577

Merged
merged 2 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ updates:
interval: weekly
allow:
- dependency-name: Castle.Core
- dependency-name: Humanizer.Core
- dependency-name: IdentityServer4.EntityFramework
- dependency-name: Microsoft.Azure.Cosmos
- dependency-name: Microsoft.CSharp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static IServiceCollection AddEntityFrameworkDesignTimeServices(
.AddSingleton<INamedConnectionStringResolver>(
new DesignTimeConnectionStringResolver(applicationServiceProviderAccessor))
.AddSingleton(reporter)
.AddSingleton<IPluralizer, NullPluralizer>()
.AddSingleton<IPluralizer, HumanizerPluralizer>()
.AddSingleton<IReverseEngineerScaffolder, ReverseEngineerScaffolder>()
.AddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.AddSingleton<IScaffoldingTypeMapper, ScaffoldingTypeMapper>()
Expand Down
5 changes: 3 additions & 2 deletions src/EFCore.Design/Design/Internal/DatabaseOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ public virtual SavedModelFiles ScaffoldContext(
bool useDataAnnotations,
bool overwriteFiles,
bool useDatabaseNames,
bool suppressOnConfiguring)
bool suppressOnConfiguring,
bool noPluralize)
{
Check.NotEmpty(provider, nameof(provider));
Check.NotEmpty(connectionString, nameof(connectionString));
Expand Down Expand Up @@ -105,7 +106,7 @@ public virtual SavedModelFiles ScaffoldContext(
var scaffoldedModel = scaffolder.ScaffoldModel(
connectionString,
new DatabaseModelFactoryOptions(tables, schemas),
new ModelReverseEngineerOptions { UseDatabaseNames = useDatabaseNames },
new ModelReverseEngineerOptions { UseDatabaseNames = useDatabaseNames, NoPluralize = noPluralize },
new ModelCodeGenerationOptions
{
UseDataAnnotations = useDataAnnotations,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Humanizer;

namespace Microsoft.EntityFrameworkCore.Design.Internal
{
/// <summary>
Expand All @@ -9,17 +11,17 @@ namespace Microsoft.EntityFrameworkCore.Design.Internal
/// 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.
/// </summary>
public class NullPluralizer : IPluralizer
public class HumanizerPluralizer : IPluralizer
{
/// <summary>
/// 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.
/// </summary>
public virtual string Pluralize(string identifier)
public virtual string Pluralize(string name)
{
return identifier;
return name?.Pluralize(inputIsKnownToBeSingular: false);
}

/// <summary>
Expand All @@ -28,9 +30,9 @@ public virtual string Pluralize(string identifier)
/// 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.
/// </summary>
public virtual string Singularize(string identifier)
public virtual string Singularize(string name)
{
return identifier;
return name?.Singularize(inputIsKnownToBePlural: false);
}
}
}
9 changes: 6 additions & 3 deletions src/EFCore.Design/Design/OperationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ public class ScaffoldContext : OperationBase
/// <para><c>useDatabaseNames</c>--Use table and column names directly from the database.</para>
/// <para><c>modelNamespace</c>--Specify to override the namespace of the generated entity types.</para>
/// <para><c>contextNamespace</c>--Specify to override the namespace of the generated DbContext class.</para>
/// <para><c>noPluralize</c>--Don't use the pluralizer.</para>
/// </summary>
/// <param name="executor"> The operation executor. </param>
/// <param name="resultHandler"> The <see cref="IOperationResultHandler" />. </param>
Expand All @@ -472,12 +473,13 @@ public ScaffoldContext(
var overwriteFiles = (bool)args["overwriteFiles"];
var useDatabaseNames = (bool)args["useDatabaseNames"];
var suppressOnConfiguring = (bool)(args["suppressOnConfiguring"] ?? false);
var noPluralize = (bool)(args["noPluralize"] ?? false);

Execute(
() => executor.ScaffoldContextImpl(
provider, connectionString, outputDir, outputDbContextDir, dbContextClassName,
schemaFilters, tableFilters, modelNamespace, contextNamespace, useDataAnnotations,
overwriteFiles, useDatabaseNames, suppressOnConfiguring));
overwriteFiles, useDatabaseNames, suppressOnConfiguring, noPluralize));
}
}

Expand All @@ -494,7 +496,8 @@ private IDictionary ScaffoldContextImpl(
bool useDataAnnotations,
bool overwriteFiles,
bool useDatabaseNames,
bool suppressOnConfiguring)
bool suppressOnConfiguring,
bool noPluarlize)
{
Check.NotNull(provider, nameof(provider));
Check.NotNull(connectionString, nameof(connectionString));
Expand All @@ -504,7 +507,7 @@ private IDictionary ScaffoldContextImpl(
var files = DatabaseOperations.ScaffoldContext(
provider, connectionString, outputDir, outputDbContextDir, dbContextClassName,
schemaFilters, tableFilters, modelNamespace, contextNamespace, useDataAnnotations,
overwriteFiles, useDatabaseNames, suppressOnConfiguring);
overwriteFiles, useDatabaseNames, suppressOnConfiguring, noPluarlize);

return new Hashtable { ["ContextFile"] = files.ContextFile, ["EntityTypeFiles"] = files.AdditionalFiles.ToArray() };
}
Expand Down
1 change: 1 addition & 0 deletions src/EFCore.Design/EFCore.Design.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.7.9" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.HostFactoryResolver.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHostFactoryResolverSourcesVersion)" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public interface IScaffoldingModelFactory
/// 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.
/// </summary>
IModel Create([NotNull] DatabaseModel databaseModel, bool useDatabaseNames);
IModel Create([NotNull] DatabaseModel databaseModel, [NotNull] ModelReverseEngineerOptions options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class RelationalScaffoldingModelFactory : IScaffoldingModelFactory
private readonly IOperationReporter _reporter;
private readonly ICandidateNamingService _candidateNamingService;
private Dictionary<DatabaseTable, CSharpUniqueNamer<DatabaseColumn>> _columnNamers;
private bool _useDatabaseNames;
private ModelReverseEngineerOptions _options;
private readonly DatabaseTable _nullTable = new DatabaseTable();
private CSharpUniqueNamer<DatabaseTable> _tableNamer;
private CSharpUniqueNamer<DatabaseTable> _dbSetNamer;
Expand Down Expand Up @@ -80,30 +80,31 @@ public RelationalScaffoldingModelFactory(
/// 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.
/// </summary>
public virtual IModel Create(DatabaseModel databaseModel, bool useDatabaseNames)
public virtual IModel Create(DatabaseModel databaseModel, ModelReverseEngineerOptions options)
{
Check.NotNull(databaseModel, nameof(databaseModel));
Check.NotNull(options, nameof(options));

var modelBuilder = new ModelBuilder(new ConventionSet());

_tableNamer = new CSharpUniqueNamer<DatabaseTable>(
useDatabaseNames
options.UseDatabaseNames
? (Func<DatabaseTable, string>)(t => t.Name)
: t => _candidateNamingService.GenerateCandidateIdentifier(t),
_cSharpUtilities,
useDatabaseNames
options.UseDatabaseNames || options.NoPluralize
? (Func<string, string>)null
: _pluralizer.Singularize);
_dbSetNamer = new CSharpUniqueNamer<DatabaseTable>(
useDatabaseNames
options.UseDatabaseNames
? (Func<DatabaseTable, string>)(t => t.Name)
: t => _candidateNamingService.GenerateCandidateIdentifier(t),
_cSharpUtilities,
useDatabaseNames
options.UseDatabaseNames || options.NoPluralize
? (Func<string, string>)null
: _pluralizer.Pluralize);
_columnNamers = new Dictionary<DatabaseTable, CSharpUniqueNamer<DatabaseColumn>>();
_useDatabaseNames = useDatabaseNames;
_options = options;

VisitDatabaseModel(modelBuilder, databaseModel);

Expand Down Expand Up @@ -147,7 +148,7 @@ protected virtual string GetPropertyName([NotNull] DatabaseColumn column)

if (!_columnNamers.ContainsKey(table))
{
if (_useDatabaseNames)
if (_options.UseDatabaseNames)
{
_columnNamers.Add(
table,
Expand Down Expand Up @@ -893,7 +894,9 @@ protected virtual void AddNavigationProperties([NotNull] IMutableForeignKey fore
if (!foreignKey.IsUnique
&& !foreignKey.IsSelfReferencing())
{
principalEndNavigationPropertyCandidateName = _pluralizer.Pluralize(principalEndNavigationPropertyCandidateName);
principalEndNavigationPropertyCandidateName = _options.NoPluralize
? principalEndNavigationPropertyCandidateName
: _pluralizer.Pluralize(principalEndNavigationPropertyCandidateName);
}

var principalEndNavigationPropertyName =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public virtual ScaffoldedModel ScaffoldModel(
databaseModel.RemoveAnnotation(ScaffoldingAnnotationNames.ConnectionString);
}

var model = _factory.Create(databaseModel, modelOptions.UseDatabaseNames);
var model = _factory.Create(databaseModel, modelOptions);

if (model == null)
{
Expand Down
6 changes: 6 additions & 0 deletions src/EFCore.Design/Scaffolding/ModelReverseEngineerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,11 @@ public class ModelReverseEngineerOptions
/// </summary>
/// <value> A value indicating whether to use the database schema names directly. </value>
public virtual bool UseDatabaseNames { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to use the pluralizer.
/// </summary>
/// <value> A value indicating whether to use the pluralizer. </value>
public virtual bool NoPluralize { get; set; }
}
}
6 changes: 5 additions & 1 deletion src/EFCore.Tools/tools/EntityFrameworkCore.PS2.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ function Remove-Migration(
.PARAMETER ContextNamespace
Specify to override the namespace for the DbContext class.

.PARAMETER NoPluralize
Don't use the pluralizer.

.LINK
about_EntityFrameworkCore
#>
Expand All @@ -208,7 +211,8 @@ function Scaffold-DbContext(
$Project,
$StartupProject,
$Namespace,
$ContextNamespace)
$ContextNamespace,
[switch] $NoPluralize)
{
throw $UpdatePowerShell
}
Expand Down
9 changes: 9 additions & 0 deletions src/EFCore.Tools/tools/EntityFrameworkCore.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,9 @@ Register-TabExpansion Scaffold-DbContext @{
.PARAMETER ContextNamespace
Specify to override the namespace for the DbContext class.

.PARAMETER NoPluralize
Don't use the pluralizer.

.PARAMETER Args
Arguments passed to the application.

Expand Down Expand Up @@ -377,6 +380,7 @@ function Scaffold-DbContext
[string] $StartupProject,
[string] $Namespace,
[string] $ContextNamespace,
[switch] $NoPluralize,
[string] $Args)

$dteProject = GetProject $Project
Expand Down Expand Up @@ -432,6 +436,11 @@ function Scaffold-DbContext
$params += '--no-onconfiguring'
}

if ($NoPluralize)
{
$params += '--no-pluralize'
}

# NB: -join is here to support ConvertFrom-Json on PowerShell 3.0
$result = (EF $dteProject $dteStartupProject $params $Args) -join "`n" | ConvertFrom-Json

Expand Down
6 changes: 6 additions & 0 deletions src/dotnet-ef/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/dotnet-ef/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,7 @@
<data name="SuppressOnConfiguringDescription" xml:space="preserve">
<value>Suppress generation of the DbContext.OnConfiguring() method.</value>
</data>
<data name="NoPluralizeDescription" xml:space="preserve">
<value>Don't use the pluralizer.</value>
</data>
</root>
2 changes: 2 additions & 0 deletions src/ef/Commands/DbContextScaffoldCommand.Configure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal partial class DbContextScaffoldCommand : ProjectCommandBase
private CommandOption _namespace;
private CommandOption _contextNamespace;
private CommandOption _suppressOnConfiguring;
private CommandOption _noPluralize;

public override void Configure(CommandLineApplication command)
{
Expand All @@ -42,6 +43,7 @@ public override void Configure(CommandLineApplication command)
_namespace = command.Option("-n|--namespace <NAMESPACE>", Resources.NamespaceDescription);
_contextNamespace = command.Option("--context-namespace <NAMESPACE>", Resources.ContextNamespaceDescription);
_suppressOnConfiguring = command.Option("--no-onconfiguring", Resources.SuppressOnConfiguringDescription);
_noPluralize = command.Option("--no-pluralize", Resources.NoPluralizeDescription);

base.Configure(command);
}
Expand Down
3 changes: 2 additions & 1 deletion src/ef/Commands/DbContextScaffoldCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ protected override int Execute(string[] args)
_useDatabaseNames.HasValue(),
_namespace.Value(),
_contextNamespace.Value(),
_suppressOnConfiguring.HasValue());
_suppressOnConfiguring.HasValue(),
_noPluralize.HasValue());
if (_json.HasValue())
{
ReportJsonResults(result);
Expand Down
3 changes: 2 additions & 1 deletion src/ef/IOperationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ IDictionary ScaffoldContext(
bool useDatabaseNames,
string entityNamespace,
string dbContextNamespace,
bool suppressOnConfiguring);
bool suppressOnConfiguring,
bool noPluralize);

string ScriptMigration(string fromMigration, string toMigration, bool idempotent, string contextType);

Expand Down
6 changes: 4 additions & 2 deletions src/ef/OperationExecutorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ public IDictionary ScaffoldContext(
bool useDatabaseNames,
string modelNamespace,
string contextNamespace,
bool suppressOnConfiguring)
bool suppressOnConfiguring,
bool noPluralize)
=> InvokeOperation<IDictionary>(
"ScaffoldContext",
new Dictionary<string, object>
Expand All @@ -162,7 +163,8 @@ public IDictionary ScaffoldContext(
["useDatabaseNames"] = useDatabaseNames,
["modelNamespace"] = modelNamespace,
["contextNamespace"] = contextNamespace,
["suppressOnConfiguring"] = suppressOnConfiguring
["suppressOnConfiguring"] = suppressOnConfiguring,
["noPluralize"] = noPluralize
});

public string ScriptMigration(
Expand Down
6 changes: 6 additions & 0 deletions src/ef/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/ef/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,7 @@
<data name="SuppressOnConfiguringDescription" xml:space="preserve">
<value>Suppress generation of the DbContext.OnConfiguring() method.</value>
</data>
<data name="NoPluralizeDescription" xml:space="preserve">
<value>Don't use the pluralizer.</value>
</data>
</root>
Loading