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

Fix for 19799. Allow override of connection string for scaffolding. #19913

Merged
merged 8 commits into from
Feb 19, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,13 @@ public static class ScaffoldingAnnotationNames
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public const string ConcurrencyToken = "ConcurrencyToken";

/// <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 const string ConnectionString = Prefix + "ConnectionString";
}
}
20 changes: 20 additions & 0 deletions src/EFCore.Design/Metadata/Internal/ScaffoldingModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,25 @@ public static void SetDatabaseName([NotNull] this IMutableModel model, [CanBeNul
model.SetAnnotation(
ScaffoldingAnnotationNames.DatabaseName,
Check.NullButNotEmpty(value, nameof(value)));

/// <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 static string GetConnectionString([NotNull] this IModel model)
=> (string)model[ScaffoldingAnnotationNames.ConnectionString];
lajones marked this conversation as resolved.
Show resolved Hide resolved

/// <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 static void SetConnectionString([NotNull] this IMutableModel model, [NotNull] string value) =>
lajones marked this conversation as resolved.
Show resolved Hide resolved
model.SetAnnotation(
ScaffoldingAnnotationNames.ConnectionString,
Check.NotEmpty(value, nameof(value)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ protected virtual void GenerateClass(
_sb.AppendLine($"public partial class {contextName} : DbContext");
_sb.AppendLine("{");

if (!string.IsNullOrEmpty(model.GetConnectionString()))
lajones marked this conversation as resolved.
Show resolved Hide resolved
{
connectionString = model.GetConnectionString();
}

using (_sb.Indent())
{
GenerateConstructors(contextName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
Expand Down Expand Up @@ -167,6 +168,37 @@ public void ScaffoldModel_works_with_named_connection_string()
Assert.DoesNotContain("#warning", result.ContextFile.Code);
}

[ConditionalFact]
public void ScaffoldModel_works_with_overridden_connection_string()
{
var resolver = new TestNamedConnectionStringResolver("Data Source=Test");
var databaseModelFactory = new TestDatabaseModelFactory();
databaseModelFactory.ScaffoldedConnectionString = "Data Source=ScaffoldedConnectionString";
var scaffolder = new ServiceCollection()
.AddEntityFrameworkDesignTimeServices()
.AddSingleton<INamedConnectionStringResolver>(resolver)
.AddSingleton<IDatabaseModelFactory>(databaseModelFactory)
.AddSingleton<IRelationalTypeMappingSource, TestRelationalTypeMappingSource>()
.AddSingleton<LoggingDefinitions, TestRelationalLoggingDefinitions>()
.AddSingleton<IProviderConfigurationCodeGenerator, TestProviderCodeGenerator>()
.AddSingleton<IAnnotationCodeGenerator, AnnotationCodeGenerator>()
.BuildServiceProvider()
.GetRequiredService<IReverseEngineerScaffolder>();

var result = scaffolder.ScaffoldModel(
"Name=DefaultConnection",
new DatabaseModelFactoryOptions(),
new ModelReverseEngineerOptions(),
new ModelCodeGenerationOptions
{
ModelNamespace = "Foo"
});

Assert.Contains("Data Source=ScaffoldedConnectionString", result.ContextFile.Code);
Assert.DoesNotContain("Name=DefaultConnection", result.ContextFile.Code);
Assert.DoesNotContain("Data Source=Test", result.ContextFile.Code);
}

private class TestNamedConnectionStringResolver : INamedConnectionStringResolver
{
private readonly string _resolvedConnectionString;
Expand All @@ -181,16 +213,24 @@ public string ResolveConnectionString(string connectionString)
private class TestDatabaseModelFactory : IDatabaseModelFactory
{
public string ConnectionString { get; set; }
public string ScaffoldedConnectionString { get; set; }

public DatabaseModel Create(string connectionString, DatabaseModelFactoryOptions options)
{
ConnectionString = connectionString;
var databaseModel = new DatabaseModel();
if (ScaffoldedConnectionString != null)
{
databaseModel[ScaffoldingAnnotationNames.ConnectionString] = ScaffoldedConnectionString;
}

return new DatabaseModel();
return databaseModel;
}

public DatabaseModel Create(DbConnection connection, DatabaseModelFactoryOptions options)
=> throw new NotImplementedException();

public string OverriddenConnectionString { get; set; }
lajones marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,17 @@ public void It_sets_gets_database_name()

Assert.Null(extensions.GetDatabaseName());
}

[ConditionalFact]
public void It_sets_gets_connection_string()
{
var model = new Model();

Assert.Null(model.GetConnectionString());

model.SetConnectionString("OverriddenConnectionString");

Assert.Equal("OverriddenConnectionString", model.GetConnectionString());
}
}
}