Skip to content

Commit

Permalink
Generate DbContext Class in a Different Location
Browse files Browse the repository at this point in the history
- Add outputDbContextDir to ReverseEngineerScaffolder.Save
- Add outputDbContextDir to OperationExecutor.ScaffoldContext
- Add outputDbContextDir to DbContextScaffoldCommand
  • Loading branch information
Anthony Sneed authored and bricelam committed Jan 19, 2018
1 parent 972b71f commit b271241
Show file tree
Hide file tree
Showing 17 changed files with 289 additions and 14 deletions.
1 change: 1 addition & 0 deletions EFCore.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INITIALIZER_BRACES/@EntryValue">NEXT_LINE</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_INITIALIZER_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/LINE_FEED_AT_FILE_END/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_CONSTRUCTOR_INITIALIZER_ON_SAME_LINE/@EntryValue">False</s:Boolean>
Expand Down
2 changes: 2 additions & 0 deletions src/EFCore.Design/Design/Internal/DatabaseOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public virtual ModelFiles ScaffoldContext(
[NotNull] string provider,
[NotNull] string connectionString,
[CanBeNull] string outputDir,
[CanBeNull] string outputContextDir,
[CanBeNull] string dbContextClassName,
[NotNull] IEnumerable<string> schemas,
[NotNull] IEnumerable<string> tables,
Expand Down Expand Up @@ -95,6 +96,7 @@ public virtual ModelFiles ScaffoldContext(
scaffoldedModel,
_projectDir,
outputDir,
outputContextDir,
overwriteFiles);
}

Expand Down
16 changes: 13 additions & 3 deletions src/EFCore.Design/Design/OperationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ public class ScaffoldContext : OperationBase
/// <para><c>connectionString</c>--The connection string to the database.</para>
/// <para><c>provider</c>--The provider to use.</para>
/// <para><c>outputDir</c>--The directory to put files in. Paths are relative to the project directory.</para>
/// <para><c>outputDbContextDir</c>--The directory to put DbContext file in. Paths are relative to the project directory.</para>
/// <para><c>dbContextClassName</c>--The name of the DbContext to generate.</para>
/// <para><c>schemaFilters</c>--The schemas of tables to generate entity types for.</para>
/// <para><c>tableFilters</c>--The tables to generate entity types for.</para>
Expand All @@ -427,6 +428,7 @@ public ScaffoldContext([NotNull] OperationExecutor executor, [NotNull] object re
var connectionString = (string)args["connectionString"];
var provider = (string)args["provider"];
var outputDir = (string)args["outputDir"];
var outputDbContextDir = (string)args["outputDbContextDir"];
var dbContextClassName = (string)args["dbContextClassName"];
var schemaFilters = (IEnumerable<string>)args["schemaFilters"];
var tableFilters = (IEnumerable<string>)args["tableFilters"];
Expand All @@ -436,8 +438,7 @@ public ScaffoldContext([NotNull] OperationExecutor executor, [NotNull] object re

Execute(
() => executor.ScaffoldContextImpl(
provider,
connectionString, outputDir, dbContextClassName,
provider, connectionString, outputDir, outputDbContextDir, dbContextClassName,
schemaFilters, tableFilters, useDataAnnotations, overwriteFiles, useDatabaseNames));
}
}
Expand All @@ -446,6 +447,7 @@ private IDictionary ScaffoldContextImpl(
[NotNull] string provider,
[NotNull] string connectionString,
[CanBeNull] string outputDir,
[CanBeNull] string outputDbContextDir,
[CanBeNull] string dbContextClassName,
[NotNull] IEnumerable<string> schemaFilters,
[NotNull] IEnumerable<string> tableFilters,
Expand All @@ -464,9 +466,17 @@ private IDictionary ScaffoldContextImpl(
{
outputDir = Path.GetFullPath(Path.Combine(_projectDir, outputDir));
}
if (!string.IsNullOrWhiteSpace(outputDbContextDir))
{
outputDbContextDir = Path.GetFullPath(Path.Combine(_projectDir, outputDbContextDir));
}
else
{
outputDbContextDir = outputDir;
}

var files = _databaseOperations.Value.ScaffoldContext(
provider, connectionString, outputDir, dbContextClassName,
provider, connectionString, outputDir, outputDbContextDir, dbContextClassName,
schemaFilters, tableFilters, useDataAnnotations, overwriteFiles, useDatabaseNames);

return new Hashtable
Expand Down
2 changes: 2 additions & 0 deletions src/EFCore.Design/Scaffolding/IReverseEngineerScaffolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ ScaffoldedModel ScaffoldModel(
/// <param name="scaffoldedModel"> The scaffolded model. </param>
/// <param name="projectDir"> The project directory. </param>
/// <param name="outputDir"> The output dirctory. </param>
/// <param name="outputDbContextDir"> The DbContext output dirctory. </param>
/// <param name="overwriteFiles"> True to overwrite any existing files. </param>
/// <returns> The model files. </returns>
ModelFiles Save(
[NotNull] ScaffoldedModel scaffoldedModel,
[NotNull] string projectDir,
[CanBeNull] string outputDir,
[CanBeNull] string outputDbContextDir,
bool overwriteFiles);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,7 @@ public CSharpDbContextGenerator(
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual string WriteCode(
IModel model,
string @namespace,
string contextName,
string connectionString,
bool useDataAnnotations)
public virtual string WriteCode(IModel model, string @namespace, string contextName, string connectionString, bool useDataAnnotations)
{
Check.NotNull(model, nameof(model));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public virtual ModelFiles Save(
ScaffoldedModel scaffoldedModel,
string projectDir,
string outputDir,
string outputDbContextDir,
bool overwriteFiles)
{
Check.NotEmpty(projectDir, nameof(projectDir));
Expand All @@ -126,12 +127,26 @@ public virtual ModelFiles Save(
? projectDir
: Path.GetFullPath(Path.Combine(projectDir, outputDir));

string outputDbContextDir1 = null;
if (outputDbContextDir == null)
{
outputDbContextDir1 = outputDir;
}
else
{
outputDbContextDir1 = Path.IsPathRooted(outputDbContextDir)
? outputDbContextDir
: Path.GetFullPath(Path.Combine(projectDir, outputDbContextDir));
}

CheckOutputFiles(scaffoldedModel, outputDir, overwriteFiles);
CheckOutputFiles(scaffoldedModel, outputDbContextDir1, overwriteFiles);

var files = new ModelFiles();
Directory.CreateDirectory(outputDir);
Directory.CreateDirectory(outputDbContextDir1);

var contextPath = Path.Combine(outputDir, scaffoldedModel.ContextFile.Path);
var contextPath = Path.Combine(outputDbContextDir1, scaffoldedModel.ContextFile.Path);
File.WriteAllText(contextPath, scaffoldedModel.ContextFile.Code, Encoding.UTF8);
files.ContextFile = contextPath;

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.

2 changes: 2 additions & 0 deletions src/ef/Commands/DbContextScaffoldCommand.Configure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal partial class DbContextScaffoldCommand : ProjectCommandBase
private CommandOption _context;
private CommandOption _force;
private CommandOption _outputDir;
private CommandOption _outputDbContextDir;
private CommandOption _schemas;
private CommandOption _tables;
private CommandOption _useDatabaseNames;
Expand All @@ -30,6 +31,7 @@ public override void Configure(CommandLineApplication command)
_context = command.Option("-c|--context <NAME>", Resources.ContextNameDescription);
_force = command.Option("-f|--force", Resources.DbContextScaffoldForceDescription);
_outputDir = command.Option("-o|--output-dir <PATH>", Resources.OutputDirDescription);
_outputDbContextDir = command.Option("--output-dbcontext-dir <PATH>", Resources.OutputDbContextDirDescription);
_schemas = command.Option("--schema <SCHEMA_NAME>...", Resources.SchemasDescription);
_tables = command.Option("-t|--table <TABLE_NAME>...", Resources.TablesDescription);
_useDatabaseNames = command.Option("--use-database-names", Resources.UseDatabaseNamesDescription);
Expand Down
1 change: 1 addition & 0 deletions src/ef/Commands/DbContextScaffoldCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected override int Execute()
_provider.Value,
_connection.Value,
_outputDir.Value(),
_outputDbContextDir.Value(),
_context.Value(),
_schemas.Values,
_tables.Values,
Expand Down
1 change: 1 addition & 0 deletions src/ef/IOperationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ IDictionary ScaffoldContext(
string provider,
string connectionString,
string outputDir,
string outputDbContextDir,
string dbContextClassName,
IEnumerable<string> schemaFilters,
IEnumerable<string> tableFilters,
Expand Down
2 changes: 2 additions & 0 deletions src/ef/OperationExecutorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public IDictionary ScaffoldContext(
string provider,
string connectionString,
string outputDir,
string outputDbContextDir,
string dbContextClassName,
IEnumerable<string> schemaFilters,
IEnumerable<string> tableFilters,
Expand All @@ -159,6 +160,7 @@ public IDictionary ScaffoldContext(
["provider"] = provider,
["connectionString"] = connectionString,
["outputDir"] = outputDir,
["outputDbContextDir"] = outputDbContextDir,
["dbContextClassName"] = dbContextClassName,
["schemaFilters"] = schemaFilters,
["tableFilters"] = tableFilters,
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 @@ -312,4 +312,7 @@
<data name="MigrationsRemoveRevertDescription" xml:space="preserve">
<value>Revert the migration if it has been applied to the database.</value>
</data>
<data name="OutputDbContextDirDescription" xml:space="preserve">
<value>The directory to put DbContext file in. Paths are relative to the project directory.</value>
</data>
</root>
67 changes: 67 additions & 0 deletions test/EFCore.Design.Tests/Design/OperationExecutorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Xunit;

namespace Microsoft.EntityFrameworkCore.Design
Expand Down Expand Up @@ -59,6 +63,69 @@ public void Execute_enumerates_results()
Assert.Equal(new[] { "Twilight Sparkle", "Princess Celestia" }, handler.Result);
}

[Theory(Skip = "DatabaseOperations.ScaffoldContext throws exception")]
[InlineData("FakeOutputDir", null)]
[InlineData("FakeOutputDir", "FakeOutputDir")]
[InlineData("FakeOutputDir", "FakeContextOutputDir")]
[InlineData("FakeOutputDir", "../AnotherFakeProject")]
[InlineData("FakeOutputDir", "../AnotherFakeProject/FakeContextOutputDir")]
[InlineData("FakeOutputDir", "rooted/AnotherFakeProject")]
[InlineData("FakeOutputDir", "rooted/AnotherFakeProject/FakeContextOutputDir")]
public void OperationExecutor_ScaffoldContext_generates_separate_context_output_path(string outputDir, string outputDbContextDir)
{
IOperationReportHandler reportHandler = new OperationReportHandler();
var resultHandler = new OperationResultHandler();
var projectPath = Path.Combine(new TempDirectory().Path, "FakeProjectDir");
var executorArgs = new Dictionary<string, object>
{
{ "targetName", "FakeTarget"},
{ "startupTargetName", "Microsoft.EntityFrameworkCore.Design.Tests"},
{ "projectDir", projectPath},
{ "rootNamespace", "FakeRootNamespace"},
{ "language", "C#"},
};
var executor = new OperationExecutor(reportHandler, executorArgs);
var connectionString = new SqlConnectionStringBuilder
{
DataSource = @"(localdb)\MSSQLLocalDB",
InitialCatalog = "CommandConfiguration",
IntegratedSecurity = true,
}.ConnectionString;

if (outputDbContextDir != null && outputDbContextDir.StartsWith("rooted"))
{
var altDirName = outputDbContextDir.Substring(7);
outputDbContextDir = Path.Combine(new TempDirectory().Path, altDirName);
}

var scaffolderArgs = new Dictionary<string, object>
{
{ "connectionString", connectionString},
{ "provider", "Microsoft.EntityFrameworkCore.SqlServer"},
{ "outputDir", outputDir},
{ "outputDbContextDir", outputDbContextDir},
{ "dbContextClassName", "FakeDbContextClassName"},
{ "schemaFilters", new[]{"FakeSchemaFilter"}},
{ "tableFilters", new[] {"FakeTableFilter"}},
{ "useDataAnnotations", false},
{ "overwriteFiles", true},
{ "useDatabaseNames", false},
};

new OperationExecutor.ScaffoldContext(executor, resultHandler, scaffolderArgs);

var files = (Hashtable)resultHandler.Result;
var fullContextPath = Path.GetDirectoryName((string)files["ContextFile"]);
var contextPath = new DirectoryInfo(fullContextPath).Name;
var expectedOutputPath = outputDir;
if (outputDbContextDir != null && outputDbContextDir != outputDir)
{
expectedOutputPath = new DirectoryInfo(outputDbContextDir).Name;
}

Assert.Equal(expectedOutputPath, contextPath);
}

private IEnumerable<string> YieldResults()
{
yield return "Twilight Sparkle";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void Save_works()
}
};

var result = scaffolder.Save(scaffoldedModel, directory.Path, "Models", overwriteFiles: false);
var result = scaffolder.Save(scaffoldedModel, directory.Path, "Models", "Models", overwriteFiles: false);

var contextPath = Path.Combine(directory.Path, "Models", "TestContext.cs");
Assert.Equal(contextPath, result.ContextFile);
Expand Down Expand Up @@ -79,7 +79,7 @@ public void Save_throws_when_existing_files()
};

var ex = Assert.Throws<OperationException>(
() => scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, overwriteFiles: false));
() => scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, outputDbContextDir: null, overwriteFiles: false));

Assert.Equal(
DesignStrings.ExistingFiles(
Expand Down Expand Up @@ -107,7 +107,7 @@ public void Save_works_when_overwriteFiles()
}
};

var result = scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, overwriteFiles: true);
var result = scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, outputDbContextDir: null, overwriteFiles: true);

Assert.Equal(path, result.ContextFile);
Assert.Equal("// Test", File.ReadAllText(path));
Expand Down Expand Up @@ -149,7 +149,7 @@ public void Save_throws_when_readonly_files()
};

var ex = Assert.Throws<OperationException>(
() => scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, overwriteFiles: true));
() => scaffolder.Save(scaffoldedModel, directory.Path, outputDir: null, outputDbContextDir: null, overwriteFiles: true));

Assert.Equal(
DesignStrings.ReadOnlyFiles(
Expand Down
Loading

0 comments on commit b271241

Please sign in to comment.