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

FEATURE: change DbContext to have injectable Model Creator #423

Merged
merged 13 commits into from Dec 22, 2023
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -26,7 +26,7 @@ jobs:
fetch-depth: 0

# java is used by sonar scanner
- name: Setup Java 11
- name: Setup Java 17
uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
Expand Down Expand Up @@ -67,7 +67,7 @@ jobs:
- name: Run Sonar Scanner begin
if: env.SONAR_TOKEN != '' && env.SONAR_PROJECT_KEY != '' && env.SONAR_ORGANISATION_KEY != ''
run: |
dotnet sonarscanner begin /k:"${{ env.SONAR_PROJECT_KEY }}" /d:sonar.login="${{ env.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /o:"${{ env.SONAR_ORGANISATION_KEY }}" /d:sonar.cs.opencover.reportsPaths="artifacts/opencover/**/*.xml"
dotnet sonarscanner begin /k:"${{ env.SONAR_PROJECT_KEY }}" /d:sonar.token="${{ env.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /o:"${{ env.SONAR_ORGANISATION_KEY }}" /d:sonar.cs.opencover.reportsPaths="artifacts/opencover/**/*.xml"
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_PROJECT_KEY: ${{ secrets.SONAR_PROJECT_KEY }}
Expand Down
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Whipstaff.AspNetCore" Version="7.1.3" />
<PackageReference Include="Whipstaff.EntityFramework" Version="7.1.3" />
<PackageReference Include="Whipstaff.Wpf" Version="7.1.3" />
<PackageReference Include="Whipstaff.Wpf.Mahapps" Version="7.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
Expand Down
Expand Up @@ -57,17 +57,16 @@ private MemberDeclarationSyntax[] GetMembers(string className, EntityGenerationM
//var constructorArguments = GetConstructorArguments();
//var baseArguments = GetBaseConstructorArguments();

//var fields = GetFieldDeclarations(constructorArguments, entityName);
//if (fields != null && fields.Length > 0)
//{
// result.AddRange(fields);
//}
var fields = GetFieldDeclarations(className);
if (fields != null && fields.Length > 0)
{
result.AddRange(fields);
}

//if (constructorArguments != null && constructorArguments.Count > 0)
//{
// result.Add(GenerateConstructor(className, constructorArguments, entityName, baseArguments));
//}
result.Add(GetDefaultConstructor(className));
result.Add(GetConstructorWithDbOptions(className));

var properties = GetPropertyDeclarations(generationModelEntityGenerationModel);
Expand All @@ -85,20 +84,13 @@ private MemberDeclarationSyntax[] GetMembers(string className, EntityGenerationM
return result.ToArray();
}

private ConstructorDeclarationSyntax GetDefaultConstructor(string className)
{
var body = new List<StatementSyntax>();

var declaration = SyntaxFactory.ConstructorDeclaration(className)
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.AddBodyStatements(body.ToArray());

return declaration;
}

private ConstructorDeclarationSyntax GetConstructorWithDbOptions(string className)
{
var parameters = GetParams(new []{ "DbContextOptions dbContextOptions"});
var parameters = GetParams(new []
{
$"DbContextOptions<{className}> dbContextOptions",
$"Func<Whipstaff.EntityFramework.ModelCreation.IModelCreator<{className}>> modelCreatorFunc"
});

var seperatedSyntaxList = new SeparatedSyntaxList<ArgumentSyntax>();

Expand All @@ -112,7 +104,29 @@ private ConstructorDeclarationSyntax GetConstructorWithDbOptions(string classNam
SyntaxKind.BaseConstructorInitializer,
baseInitializerArgumentList);

var body = new List<StatementSyntax>();
var body = new List<StatementSyntax>
{
RoslynGenerationHelpers.GetNullGuardCheckSyntax("modelCreatorFunc"),
};

var left = SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.ThisExpression(),
SyntaxFactory.Token(SyntaxKind.DotToken),
SyntaxFactory.IdentifierName(SyntaxFactory.Identifier($"_modelCreatorFunc")));

var right = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier("modelCreatorFunc"));

var assignment = SyntaxFactory.ExpressionStatement(
SyntaxFactory.AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
left,
SyntaxFactory.Token(SyntaxKind.EqualsToken),
right),
SyntaxFactory.Token(SyntaxKind.SemicolonToken)
);

body.Add(assignment);

var declaration = SyntaxFactory.ConstructorDeclaration(className)
.WithParameterList(parameters)
Expand Down Expand Up @@ -168,32 +182,21 @@ private PropertyDeclarationSyntax[] GetPropertyDeclarations(EntityGenerationMode
return result;
}

//private MemberDeclarationSyntax[] GetFieldDeclarations(
// IList<Tuple<Func<string, string>, string, Accessibility>> constructorArguments,
// string entityName)
//{
// if (constructorArguments == null || constructorArguments.Count < 1)
// {
// return null;
// }

// var result = new List<MemberDeclarationSyntax>();

// foreach (var constructorArgument in constructorArguments)
// {
// var fieldType = constructorArgument.Item1(entityName);

// var fieldDeclaration = SyntaxFactory.FieldDeclaration(
// SyntaxFactory.VariableDeclaration(
// SyntaxFactory.ParseTypeName(fieldType),
// SyntaxFactory.SeparatedList(new[] { SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier($"_{constructorArgument.Item2}")) })
// ))
// .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));
// result.Add(fieldDeclaration);
// }

// return result.ToArray();
//}
private MemberDeclarationSyntax[] GetFieldDeclarations(string className)
{

var result = new List<MemberDeclarationSyntax>();

var fieldDeclaration = SyntaxFactory.FieldDeclaration(
SyntaxFactory.VariableDeclaration(
SyntaxFactory.ParseTypeName($"Func<Whipstaff.EntityFramework.ModelCreation.IModelCreator<{className}>>"),
SyntaxFactory.SeparatedList(new[] { SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier($"_modelCreatorFunc")) })
))
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword));
result.Add(fieldDeclaration);

return result.ToArray();
}

private MemberDeclarationSyntax GetClassDeclarationSyntax(EntityFrameworkDbContextGenerationModel generationModelEntityGenerationModel, string suffix)
{
Expand Down Expand Up @@ -342,26 +345,35 @@ private MemberDeclarationSyntax GetOnModelCreatingMethodDeclaration(EntityGenera
{
var methodName = $"OnModelCreating";

var body = generationModelEntityGenerationModel.Select(GetApplyConfigurationInvocationDeclaration).ToArray();
var body = new List<StatementSyntax>
{
RoslynGenerationHelpers.GetMethodOnVariableInvocationSyntax(
"base",
methodName,
new [] { "modelBuilder" },
false),
RoslynGenerationHelpers.GetVariableAssignmentFromFuncVariableInvocationSyntax(
"modelCreator",
"_modelCreatorFunc",
Array.Empty<string>(),
false),
RoslynGenerationHelpers.GetMethodOnVariableInvocationSyntax(
"modelCreator",
"CreateModel",
new [] { "modelBuilder" },
false),
};

var parameters = GetParams(new []{ $"Microsoft.EntityFrameworkCore.ModelBuilder modelBuilder"});

var inheritDocSyntaxTrivia = RoslynGenerationHelpers.GetInheritDocSyntaxTrivia();
var returnType = SyntaxFactory.ParseTypeName("void");
var declaration = SyntaxFactory.MethodDeclaration(returnType, methodName)
.WithParameterList(parameters)
.AddModifiers(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword), SyntaxFactory.Token(SyntaxKind.OverrideKeyword))
.AddBodyStatements(body.ToArray());
.AddBodyStatements(body.ToArray())
.WithLeadingTrivia(inheritDocSyntaxTrivia);
return declaration;
}

private StatementSyntax GetApplyConfigurationInvocationDeclaration(EntityGenerationModel entityGenerationModel)
{
var invokeExpression = RoslynGenerationHelpers.GetMethodOnVariableInvocationSyntax("modelBuilder",
"ApplyConfiguration",
new[] {$"new EntityTypeConfigurations.{entityGenerationModel.ClassName}EntityTypeConfiguration()"},
false);

return invokeExpression;
}
}
}
Expand Up @@ -518,11 +518,11 @@ private ExpressionSyntax CheckRequiredMethodDeclaration(ExpressionSyntax fluentA

private void DoPrimaryKeyMethodDeclaration(List<StatementSyntax> body)
{
var statement =
RoslynGenerationHelpers.GetMethodOnVariableInvocationSyntax(
var statement = RoslynGenerationHelpers.GetMethodOnVariableInvocationSyntax(
"builder",
"HasKey",
new[] {$"x => x.Id"}, false);
new[] {$"x => x.Id"},
false);
body.Add(statement);
}
}
Expand Down
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using Dhgms.Nucleotide.Generators.Features.Common.AttributeGenerators;
using Dhgms.Nucleotide.Generators.GeneratorProcessors;
using Dhgms.Nucleotide.Generators.PropertyInfo;
Expand All @@ -24,7 +25,25 @@ public sealed class EntityFrameworkModelGeneratorProcessor : BaseClassLevelCodeG
///<inheritdoc />
protected override IEnumerable<PropertyDeclarationSyntax> GetPropertyDeclarations(EntityFrameworkModelEntityGenerationModel entityGenerationModel)
{
var inheritDocSyntaxTrivia = RoslynGenerationHelpers.GetInheritDocSyntaxTrivia();
var inheritDocSyntaxTrivia = RoslynGenerationHelpers.GetInheritDocSyntaxTrivia().ToArray();
var datetimeOffSetType = SyntaxFactory.ParseTypeName("System.DateTimeOffset");
var ulongType = SyntaxFactory.ParseTypeName("ulong");

yield return RoslynGenerationHelpers.GetPropertyDeclarationSyntax(
datetimeOffSetType,
$"Created",
inheritDocSyntaxTrivia);

yield return RoslynGenerationHelpers.GetPropertyDeclarationSyntax(
datetimeOffSetType,
$"Modified",
inheritDocSyntaxTrivia);

yield return RoslynGenerationHelpers.GetPropertyDeclarationSyntax(
ulongType,
$"RowVersion",
inheritDocSyntaxTrivia);

if (entityGenerationModel?.ParentEntityRelationships != null)
{
foreach (var referencedByEntityGenerationModel in entityGenerationModel.ParentEntityRelationships)
Expand Down Expand Up @@ -145,6 +164,9 @@ protected override string GetBaseClass(EntityFrameworkModelEntityGenerationModel
///<inheritdoc />
protected override IEnumerable<string> GetImplementedInterfaces(EntityFrameworkModelEntityGenerationModel entityGenerationModel)
{
yield return $"global::Whipstaff.Core.Entities.ILongRowVersion";
yield return $"global::Whipstaff.Core.Entities.IModifiable";

if (entityGenerationModel?.ParentEntityRelationships != null)
{
foreach (var referencedByEntityGenerationModel in entityGenerationModel.ParentEntityRelationships)
Expand Down
@@ -0,0 +1,20 @@
// Copyright (c) 2020 DHGMS Solutions and Contributors. All rights reserved.
// DHGMS Solutions and Contributors licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using Dhgms.Nucleotide.Generators.Generators;

namespace Dhgms.Nucleotide.Generators.Features.EntityFramework
{
/// <summary>
/// Code Generator for Entity Framework Injectable Model Creator.
/// </summary>
public abstract class EntityFrameworkMsSqlModelCreatorGenerator : BaseGenerator<EntityFrameworkDbContextFeatureFlags, EntityFrameworkMsSqlModelCreatorGeneratorProcessor, EntityFrameworkDbContextGenerationModel>
{
///<inheritdoc />
protected override string GetNamespace()
{
return "ModelCreation";
}
}
}