Skip to content

Commit

Permalink
adding nullable entity sets if nullable is enabled for existing db co…
Browse files Browse the repository at this point in the history
…ntexts. (#1891)
  • Loading branch information
deepchoudhery authored May 9, 2022
1 parent 28fb3a8 commit e8f9fb4
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 11 deletions.
5 changes: 3 additions & 2 deletions src/Scaffolding/VS.Web.CG.EFCore/DbContextEditorServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ private async Task<SyntaxTree> AddNewContextItemsInternal(string templateName, N
}


public EditSyntaxTreeResult AddModelToContext(ModelType dbContext, ModelType modelType)
public EditSyntaxTreeResult AddModelToContext(ModelType dbContext, ModelType modelType, bool nullableEnabled)
{
if (!IsModelPropertyExists(dbContext.TypeSymbol, modelType.FullName))
{
Expand All @@ -112,9 +112,10 @@ public EditSyntaxTreeResult AddModelToContext(ModelType dbContext, ModelType mod
var lastNode = dbContextNode.ChildNodes().Last();

var safeModelName = GetSafeModelName(modelType.Name, dbContext.TypeSymbol);
var nullablilitySign = nullableEnabled ? "? " : " ";
// Todo : Need pluralization for property name below.
// It is not always safe to just use DbSet<modelType.Name> as there can be multiple class names in different namespaces.
var dbSetProperty = "public DbSet<" + modelType.FullName + "> " + safeModelName + " { get; set; }" + Environment.NewLine;
var dbSetProperty = "public DbSet<" + modelType.FullName + ">" + nullablilitySign + safeModelName + " { get; set; }" + Environment.NewLine;
var propertyDeclarationWrapper = CSharpSyntaxTree.ParseText(dbSetProperty);

var newNode = rootNode.InsertNodesAfter(lastNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public async Task Process()
}
else if (TryGetDbContextSymbolInWebProject(dbContextSymbols, out dbContextSymbolInWebProject))
{
await AddModelTypeToExistingDbContextIfNeeded(dbContextSymbolInWebProject);
await AddModelTypeToExistingDbContextIfNeeded(dbContextSymbolInWebProject, _applicationInfo);
}
else
{
Expand Down Expand Up @@ -174,7 +174,7 @@ public async Task Process()
}
else if (TryGetDbContextSymbolInWebProject(dbContextSymbols, out dbContextSymbolInWebProject))
{
await AddModelTypeToExistingDbContextIfNeeded(dbContextSymbolInWebProject);
await AddModelTypeToExistingDbContextIfNeeded(dbContextSymbolInWebProject, _applicationInfo);
}
else
{
Expand Down Expand Up @@ -305,9 +305,10 @@ private async Task EnsureDbContextInLibraryIsValid(ModelType dbContextSymbol)
}
}

private async Task AddModelTypeToExistingDbContextIfNeeded(ModelType dbContextSymbol)
private async Task AddModelTypeToExistingDbContextIfNeeded(ModelType dbContextSymbol, IApplicationInfo appInfo)
{
var addResult = _dbContextEditorServices.AddModelToContext(dbContextSymbol, _modelTypeSymbol);
bool nullabledEnabled = "enable".Equals(appInfo?.WorkspaceHelper?.GetMsBuildProperty("Nullable"), StringComparison.OrdinalIgnoreCase);
var addResult = _dbContextEditorServices.AddModelToContext(dbContextSymbol, _modelTypeSymbol, nullabledEnabled);
var projectCompilation = await _workspace.CurrentSolution.Projects
.First(project => project.AssemblyName == _projectContext.AssemblyName)
.GetCompilationAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface IDbContextEditorServices
{
Task<SyntaxTree> AddNewContext(NewDbContextTemplateModel dbContextTemplateModel);

EditSyntaxTreeResult AddModelToContext(ModelType dbContext, ModelType modelType);
EditSyntaxTreeResult AddModelToContext(ModelType dbContext, ModelType modelType, bool nullableEnabled);

EditSyntaxTreeResult EditStartupForNewContext(ModelType startup, string dbContextTypeName, string dbContextNamespace, string dataBaseName, bool useSqlite);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,41 @@ public void AddModelToContext_Adds_Model_From_Same_Project_To_Context(string bef
var modelType = ModelType.FromITypeSymbol(types.Where(ts => ts.Name == "MyModel").First());
var contextType = ModelType.FromITypeSymbol(types.Where(ts => ts.Name == "MyContext").First());

var result = testObj.AddModelToContext(contextType, modelType);
var result = testObj.AddModelToContext(contextType, modelType, nullableEnabled: false);

Assert.True(result.Edited);

Assert.Equal(afterDbContextText, result.NewTree.GetText().ToString(), ignoreCase: false, ignoreLineEndingDifferences: true);
}

[Theory]
[InlineData("DbContext_Before.txt", "MyModel.txt", "DbContextNullable_After.txt")]
public void AddModelToContext_Adds_Model_From_Same_Project_To_Context_With_Nullable_Enabled(string beforeContextResource, string modelResource, string afterContextResource)
{
string resourcePrefix = "compiler/resources/";

var beforeDbContextText = ResourceUtilities.GetEmbeddedResourceFileContent(resourcePrefix + beforeContextResource);
var modelText = ResourceUtilities.GetEmbeddedResourceFileContent(resourcePrefix + modelResource);
var afterDbContextText = ResourceUtilities.GetEmbeddedResourceFileContent(resourcePrefix + afterContextResource);

var contextTree = CSharpSyntaxTree.ParseText(beforeDbContextText);
var modelTree = CSharpSyntaxTree.ParseText(modelText);
var efReference = MetadataReference.CreateFromFile(Assembly.GetEntryAssembly().Location);

var compilation = CSharpCompilation.Create("DoesNotMatter", new[] { contextTree, modelTree }, new[] { efReference });

DbContextEditorServices testObj = GetTestObject();

var types = RoslynUtilities.GetDirectTypesInCompilation(compilation);
var modelType = ModelType.FromITypeSymbol(types.Where(ts => ts.Name == "MyModel").First());
var contextType = ModelType.FromITypeSymbol(types.Where(ts => ts.Name == "MyContext").First());

var result = testObj.AddModelToContext(contextType, modelType, nullableEnabled: true);

Assert.True(result.Edited);
Assert.Equal(afterDbContextText, result.NewTree.GetText().ToString(), ignoreCase: false, ignoreLineEndingDifferences: true);
}

[Theory]
[InlineData("Startup_RegisterContext_Before.txt", "Startup_RegisterContext_After.txt", "DbContext_Before.txt")]
[InlineData("Startup_Empty_Method_RegisterContext_Before.txt", "Startup_Empty_Method_RegisterContext_After.txt", "DbContext_Before.txt")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.EntityFrameworkCore;
using ModelNamespace;
namespace ContextNamespace
{
public class MyContext : DbContext
{
public MyContext() : base()
{
}
public DbSet<ModelNamespace.MyModel>? MyModel { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ namespace ContextNamespace
}
public DbSet<ModelNamespace.MyModel> MyModel { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace ContextNamespace
namespace ContextNamespace
{
public class MyContext : DbContext
{
public MyContext() : base()
{
}
}
}
}

0 comments on commit e8f9fb4

Please sign in to comment.