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

Adding support for EF Core 7 and strongly typed entity IDs #2

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 10 additions & 2 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
dotnet-version: '7.0.x'
include-prerelease: true
- name: Extend PackageVersion with build number in Directory.Build.props
shell: pwsh
run: |
Write-Host New version uses build number $env:GITHUB_RUN_NUMBER
$replacement="<PackageVersion>`$2.$($env:GITHUB_RUN_NUMBER)</PackageVersion>"
(Get-Content Directory.Build.props) -replace '(<PackageVersion>)(\d+\.\d+\.\d+)(\.\d+)(</PackageVersion>)', $replacement | Out-File Directory.Build.props
- name: Extend PackageVersion with beta tag in Directory.Build.props
if: github.ref != 'refs/heads/main'
shell: pwsh
run: |
Write-Host Adding beta tag
$date = Get-Date -Format yyyyMMddHHmmss
$replacement="<PackageVersion>`$2-beta$($date)</PackageVersion>"
(Get-Content Directory.Build.props) -replace '(<PackageVersion>)(\d+\.\d+\.\d+.\d+)(</PackageVersion>)', $replacement | Out-File Directory.Build.props
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand All @@ -37,7 +46,6 @@ jobs:
name: packages
path: '**/*.nupkg'
- name: Push to nuget.org
if: github.ref == 'refs/heads/main'
run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${NUGET_API_KEY}
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
6 changes: 3 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)prodot-Default.ruleset</CodeAnalysisRuleSet>
<VersionPrefix>6.0.0</VersionPrefix>
<PackageVersion>6.0.0.0</PackageVersion>
<VersionPrefix>7.0.0</VersionPrefix>
<PackageVersion>7.0.0.0</PackageVersion>
<TargetFramework>net6.0</TargetFramework>
<Deterministic>true</Deterministic>
<LangVersion>10.0</LangVersion>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DocumentationFile>bin\docs\$(MSBuildProjectName).xml</DocumentationFile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,15 @@
<Company>prodot GmbH</Company>
</PropertyGroup>

<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Update="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,16 @@
<ItemGroup>
<ProjectReference Include="..\Prodot.Patterns.Cqrs.Abstractions\Prodot.Patterns.Cqrs.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Update="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions Prodot.Patterns.Cqrs.EfCore/CountQueryHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class CountQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, int>
public abstract class CountQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, int>
where TQuery : CountQuery<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;

Expand Down
6 changes: 3 additions & 3 deletions Prodot.Patterns.Cqrs.EfCore/CreateQueryHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class CreateQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, TIdentifier>
public abstract class CreateQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, TIdentifier>
where TQuery : CreateQuery<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;
private readonly IMapper _mapper;
Expand All @@ -32,7 +32,7 @@ public async Task<Option<TIdentifier>> RunQueryAsync(TQuery query, CancellationT
await context.Set<TEntity>().AddAsync(entity, cancellationToken).ConfigureAwait(false);
await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

return Identifier<TIdentifierValue, TIdentifier>.From(entity.Id);
return _mapper.Map<TIdentifier>(entity.Id);
}
}

Expand Down
12 changes: 8 additions & 4 deletions Prodot.Patterns.Cqrs.EfCore/DeleteCommandHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class DeleteCommandHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, Unit>
public abstract class DeleteCommandHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, Unit>
where TQuery : DeleteCommand<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;
private readonly IMapper _mapper;

protected DeleteCommandHandlerBase(IDbContextFactory<TContext> contextFactory)
protected DeleteCommandHandlerBase(IMapper mapper, IDbContextFactory<TContext> contextFactory)
{
_mapper = mapper;
_contextFactory = contextFactory;
}

Expand All @@ -20,8 +22,10 @@ public async Task<Option<Unit>> RunQueryAsync(TQuery query, CancellationToken ca
{
using (var context = await _contextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false))
{
var entityId = _mapper.Map<TEntityIdentifier>(query.Id);

var entity = await context.Set<TEntity>()
.FirstOrDefaultAsync(cp => cp.Id!.Equals(query.Id.Value), cancellationToken)
.FirstOrDefaultAsync(cp => cp.Id!.Equals(entityId), cancellationToken)
.ConfigureAwait(false);

if (entity == null)
Expand Down
6 changes: 3 additions & 3 deletions Prodot.Patterns.Cqrs.EfCore/ListOfModelQueryHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class ListOfModelQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, IReadOnlyList<TModel>>
public abstract class ListOfModelQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, IReadOnlyList<TModel>>
where TQuery : ListOfModelQuery<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;
private readonly IMapper _mapper;
Expand All @@ -26,7 +26,7 @@ public async Task<Option<IReadOnlyList<TModel>>> RunQueryAsync(TQuery query, Can

if (query.Ids.IsSome)
{
var ids = query.Ids.Get().Select(id => id.Value).Distinct().ToList();
var ids = query.Ids.Get().Select(_mapper.Map<TEntityIdentifier>).Distinct().ToList();
databaseQuery = databaseQuery
.Where(e => ids.Contains(e.Id));
}
Expand Down
15 changes: 13 additions & 2 deletions Prodot.Patterns.Cqrs.EfCore/Prodot.Patterns.Cqrs.EfCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,23 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="11.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="AutoMapper" Version="11.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-preview.7.22376.2" />
<PackageReference Include="Prodot.Patterns.Cqrs.EfCore.Abstractions" Version="[6.0.0,7.0.0)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Prodot.Patterns.Cqrs.EfCore.Abstractions\Prodot.Patterns.Cqrs.EfCore.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Update="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
7 changes: 4 additions & 3 deletions Prodot.Patterns.Cqrs.EfCore/SingleModelQueryHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class SingleModelQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, TModel>
public abstract class SingleModelQueryHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, TModel>
where TQuery : SingleModelQuery<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;
private readonly IMapper _mapper;
Expand All @@ -22,10 +22,11 @@ public async Task<Option<TModel>> RunQueryAsync(TQuery query, CancellationToken
{
using (var context = await _contextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false))
{
var entityId = _mapper.Map<TEntityIdentifier>(query.Id);
var databaseQuery = AddIncludes(context.Set<TEntity>().AsNoTracking());

var entity = await databaseQuery
.FirstOrDefaultAsync(cp => cp.Id!.Equals(query.Id.Value), cancellationToken)
.FirstOrDefaultAsync(cp => cp.Id!.Equals(entityId), cancellationToken)
.ConfigureAwait(false);

return entity == null ? Option.None : Option.From(_mapper.Map<TModel>(entity));
Expand Down
7 changes: 4 additions & 3 deletions Prodot.Patterns.Cqrs.EfCore/UpdateCommandHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace Prodot.Patterns.Cqrs.EfCore;

public abstract class UpdateCommandHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity> : IQueryHandler<TQuery, Unit>
public abstract class UpdateCommandHandlerBase<TQuery, TModel, TIdentifier, TIdentifierValue, TContext, TEntity, TEntityIdentifier> : IQueryHandler<TQuery, Unit>
where TQuery : UpdateCommand<TModel, TIdentifier, TIdentifierValue, TQuery>
where TModel : ModelBase<TIdentifier, TIdentifierValue>
where TIdentifier : Identifier<TIdentifierValue, TIdentifier>, new()
where TContext : DbContext
where TEntity : class, IIdentifiableEntity<TIdentifierValue>
where TEntity : class, IIdentifiableEntity<TEntityIdentifier>
{
private readonly IDbContextFactory<TContext> _contextFactory;
private readonly IMapper _mapper;
Expand All @@ -22,10 +22,11 @@ public async Task<Option<Unit>> RunQueryAsync(TQuery query, CancellationToken ca
{
using (var context = await _contextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false))
{
var entityId = _mapper.Map<TEntityIdentifier>(query.UpdatedModel.Id);
var entity = _mapper.Map<TEntity>(query.UpdatedModel);

var existingEntity = await context.Set<TEntity>()
.FirstOrDefaultAsync(e => e.Id!.Equals(query.UpdatedModel.Id.Value), cancellationToken)
.FirstOrDefaultAsync(e => e.Id!.Equals(entityId), cancellationToken)
.ConfigureAwait(false);

if (existingEntity == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>Prodot.Patterns.Cqrs.MicrosoftExtensionsDependencyInjection</PackageId>
Expand All @@ -10,12 +10,23 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0-preview.7.22375.6" />
<PackageReference Include="Prodot.Patterns.Cqrs" Version="[6.0.0,7.0.0)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Prodot.Patterns.Cqrs\Prodot.Patterns.Cqrs.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Update="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions Prodot.Patterns.Cqrs/Prodot.Patterns.Cqrs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,15 @@
<ProjectReference Include="..\Prodot.Patterns.Cqrs.Abstractions\Prodot.Patterns.Cqrs.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="AsyncFixer" Version="1.6.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Update="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"sdk": {
"version": "6.0.100",
"version": "7.0.100",
"rollForward": "latestFeature",
"allowPrerelease": false
"allowPrerelease": true
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class CountQueryHandlerTests : EfCoreTestBase
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class CreateQueryHandlerTests : EfCoreTestBase
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class DeleteCommandHandlerTests : EfCoreTestBase
{
Expand Down Expand Up @@ -31,7 +31,7 @@ public async Task RunQueryAsync_DeletesEntityCorrectly()
{
Id = TestModelId.From(entity2.Id)
};
var subjectUnderTest = new TestModelDeleteCommandHandler(ContextFactory);
var subjectUnderTest = new TestModelDeleteCommandHandler(Mapper, ContextFactory);

// Act
var result = await subjectUnderTest.RunQueryAsync(query, default);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class ListOfModelQueryHandlerTests : EfCoreTestBase
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class SingleModelQueryHandlerTests : EfCoreTestBase
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;

namespace Prodot.Patterns.Cqrs.EfCore.Tests;
namespace Prodot.Patterns.Cqrs.EfCore.Tests.DirectIdTests;

public class UpdateCommandHandlerTests : EfCoreTestBase
{
Expand Down
7 changes: 7 additions & 0 deletions tests/Prodot.Patterns.Cqrs.EfCore.Tests/EfCoreTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ protected EfCoreTestBase()
.ConvertUsing((tmid, _) => tmid.Value);
o.CreateMap<int, TestModelId>()
.ConvertUsing((id, _) => TestModelId.From(id));

o.CreateMap<TestModelStrongId, TestEntityStrongId>().ReverseMap();
o.CreateMap<TestEntityStrongId, TestEntityStrongId>();
o.CreateMap<TestModelStrongId.Identifier, TestEntityStrongId.Identifier>()
.ConvertUsing((tmid, _) => new TestEntityStrongId.Identifier(tmid.Value));
o.CreateMap<TestEntityStrongId.Identifier, TestModelStrongId.Identifier>()
.ConvertUsing((id, _) => TestModelStrongId.Identifier.From(id.Value));
})
.CreateMapper();

Expand Down
Loading