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

v1: Entity Framework migration #963

Open
wants to merge 1 commit into
base: develop-v1
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions EventFlow.sln
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventFlow.MongoDB", "Source
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventFlow.MongoDB.Tests", "Source\EventFlow.MongoDB.Tests\EventFlow.MongoDB.Tests.csproj", "{9132960E-9496-4C77-BD80-A09A86814757}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EntityFramework", "EntityFramework", "{2EAEC5A8-CE58-47F6-AB61-F78FECE714D5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventFlow.EntityFramework", "Source\EventFlow.EntityFramework\EventFlow.EntityFramework.csproj", "{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -99,6 +103,10 @@ Global
{9132960E-9496-4C77-BD80-A09A86814757}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9132960E-9496-4C77-BD80-A09A86814757}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9132960E-9496-4C77-BD80-A09A86814757}.Release|Any CPU.Build.0 = Release|Any CPU
{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -118,6 +126,8 @@ Global
{9B07B6E9-428A-42F7-AFB1-B23755A409EE} = {5EE323DE-E69B-451A-8AC3-22DD6A004FBA}
{BF9A0D20-4F8E-443C-8F36-5DD854D188C2} = {9B07B6E9-428A-42F7-AFB1-B23755A409EE}
{9132960E-9496-4C77-BD80-A09A86814757} = {9B07B6E9-428A-42F7-AFB1-B23755A409EE}
{2EAEC5A8-CE58-47F6-AB61-F78FECE714D5} = {5EE323DE-E69B-451A-8AC3-22DD6A004FBA}
{5B2CBCD6-C8E1-44B9-A258-AE2A252B00E3} = {2EAEC5A8-CE58-47F6-AB61-F78FECE714D5}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {17607E2C-4E8E-45A2-85BD-0A5808E1C0F3}
Expand Down
18 changes: 9 additions & 9 deletions Source/EventFlow.EntityFramework/EntityFrameworkConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using EventFlow.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace EventFlow.EntityFramework
{
public class EntityFrameworkConfiguration : IEntityFrameworkConfiguration
{
private Action<IServiceRegistration> _registerUniqueConstraintDetectionStrategy;
private Action<IServiceRegistration> _registerBulkOperationConfiguration;
private Action<IServiceCollection> _registerUniqueConstraintDetectionStrategy;
private Action<IServiceCollection> _registerBulkOperationConfiguration;

public static EntityFrameworkConfiguration New => new EntityFrameworkConfiguration();

Expand All @@ -39,24 +39,24 @@ private EntityFrameworkConfiguration()
UseBulkOperationConfiguration<DefaultBulkOperationConfiguration>();
}

void IEntityFrameworkConfiguration.Apply(IServiceRegistration serviceRegistration)
void IEntityFrameworkConfiguration.Apply(IServiceCollection serviceCollection)
{
serviceRegistration.Register<IEntityFrameworkConfiguration>(s => this);
_registerUniqueConstraintDetectionStrategy(serviceRegistration);
_registerBulkOperationConfiguration(serviceRegistration);
serviceCollection.AddTransient<IEntityFrameworkConfiguration>(s => this);
_registerUniqueConstraintDetectionStrategy(serviceCollection);
_registerBulkOperationConfiguration(serviceCollection);
}

public EntityFrameworkConfiguration UseBulkOperationConfiguration<T>()
where T : class, IBulkOperationConfiguration
{
_registerBulkOperationConfiguration = s => s.Register<IBulkOperationConfiguration, T>();
_registerBulkOperationConfiguration = s => s.AddTransient<IBulkOperationConfiguration, T>();
return this;
}

public EntityFrameworkConfiguration UseUniqueConstraintDetectionStrategy<T>()
where T : class, IUniqueConstraintDetectionStrategy
{
_registerUniqueConstraintDetectionStrategy = s => s.Register<IUniqueConstraintDetectionStrategy, T>();
_registerUniqueConstraintDetectionStrategy = s => s.AddTransient<IUniqueConstraintDetectionStrategy, T>();
return this;
}
}
Expand Down
16 changes: 11 additions & 5 deletions Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../Common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>netstandard2.1;netcoreapp3.1;net6.0</TargetFrameworks>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<GenerateAssemblyInfo>True</GenerateAssemblyInfo>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<Title>EventFlow.EntityFramework</Title>
<Authors>Frank Ebersoll</Authors>
<Company>Rasmus Mikkelsen</Company>
<Copyright>Copyright (c) Rasmus Mikkelsen 2015 - 2021</Copyright>
<Copyright>Copyright (c) Rasmus Mikkelsen 2015 - 2022</Copyright>
<Description>Entity Framework Core support for EventFlow</Description>
<PackageTags>CQRS ES event sourcing EF Entity Framework Core</PackageTags>
<RepositoryType>git</RepositoryType>
Expand All @@ -20,15 +20,21 @@
<PackageReleaseNotes>UPDATED BY BUILD</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
<PackageReference Include="Microsoft.EntityFrameworkCore">
<Version>3.1.5</Version>
<Version>3.1.31</Version>
</PackageReference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Microsoft.EntityFrameworkCore">
<Version>3.1.1</Version>
<Version>3.1.31</Version>
</PackageReference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore">
<Version>6.0.11</Version>
</PackageReference>
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,24 @@
using EventFlow.EntityFramework.Extensions;
using EventFlow.EventStores;
using EventFlow.Exceptions;
using EventFlow.Logs;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace EventFlow.EntityFramework.EventStores
{
public class EntityFrameworkEventPersistence<TDbContext> : IEventPersistence
where TDbContext : DbContext
{
private readonly ILogger<EntityFrameworkEventPersistence<TDbContext>> _logger;
private readonly IDbContextProvider<TDbContext> _contextProvider;
private readonly ILog _log;
private readonly IUniqueConstraintDetectionStrategy _strategy;

public EntityFrameworkEventPersistence(
ILog log,
ILogger<EntityFrameworkEventPersistence<TDbContext>> logger,
IDbContextProvider<TDbContext> contextProvider,
IUniqueConstraintDetectionStrategy strategy
)
IUniqueConstraintDetectionStrategy strategy)
{
_log = log;
_logger = logger;
_contextProvider = contextProvider;
_strategy = strategy;
}
Expand All @@ -61,29 +60,29 @@ IUniqueConstraintDetectionStrategy strategy
? 0
: long.Parse(globalPosition.Value);

using (var context = _contextProvider.CreateContext())
{
var entities = await context
.Set<EventEntity>()
.OrderBy(e => e.GlobalSequenceNumber)
.Where(e => e.GlobalSequenceNumber >= startPosition)
.Take(pageSize)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

var nextPosition = entities.Any()
? entities.Max(e => e.GlobalSequenceNumber) + 1
: startPosition;

return new AllCommittedEventsPage(new GlobalPosition(nextPosition.ToString()), entities);
}
await using var context = _contextProvider.CreateContext();

var entities = await context
.Set<EventEntity>()
.OrderBy(e => e.GlobalSequenceNumber)
.Where(e => e.GlobalSequenceNumber >= startPosition)
.Take(pageSize)
.ToListAsync(cancellationToken);

var nextPosition = entities.Any()
? entities.Max(e => e.GlobalSequenceNumber) + 1
: startPosition;

return new AllCommittedEventsPage(new GlobalPosition(nextPosition.ToString()), entities);
}

public async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync(IIdentity id,
IReadOnlyCollection<SerializedEvent> serializedEvents, CancellationToken cancellationToken)
{
if (!serializedEvents.Any())
return new ICommittedDomainEvent[0];
{
return Array.Empty<ICommittedDomainEvent>();
}

var entities = serializedEvents
.Select((e, i) => new EventEntity
Expand All @@ -97,24 +96,22 @@ IUniqueConstraintDetectionStrategy strategy
})
.ToList();

_log.Verbose(
"Committing {0} events to EntityFramework event store for entity with ID '{1}'",
_logger.LogTrace(
"Committing {Count} events to EntityFramework event store for entity with ID '{Id}'",
entities.Count,
id);

try
{
using (var context = _contextProvider.CreateContext())
{
await context.AddRangeAsync(entities, cancellationToken);
await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
await using var context = _contextProvider.CreateContext();
await context.AddRangeAsync(entities, cancellationToken);
await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
catch (DbUpdateException ex) when (ex.IsUniqueConstraintViolation(_strategy))
{
_log.Verbose(
_logger.LogTrace(
"Entity Framework event insert detected an optimistic concurrency " +
"exception for entity with ID '{0}'", id);
"exception for entity with ID '{Id}'", id);
throw new OptimisticConcurrencyException(ex.Message, ex);
}

Expand All @@ -124,38 +121,34 @@ IUniqueConstraintDetectionStrategy strategy
public async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCommittedEventsAsync(IIdentity id,
int fromEventSequenceNumber, CancellationToken cancellationToken)
{
using (var context = _contextProvider.CreateContext())
{
var entities = await context
.Set<EventEntity>()
.Where(e => e.AggregateId == id.Value
&& e.AggregateSequenceNumber >= fromEventSequenceNumber)
.OrderBy(e => e.AggregateSequenceNumber)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

return entities;
}
await using var context = _contextProvider.CreateContext();

var entities = await context
.Set<EventEntity>()
.Where(e => e.AggregateId == id.Value
&& e.AggregateSequenceNumber >= fromEventSequenceNumber)
.OrderBy(e => e.AggregateSequenceNumber)
.ToListAsync(cancellationToken);

return entities;
}

public async Task DeleteEventsAsync(IIdentity id, CancellationToken cancellationToken)
{
using (var context = _contextProvider.CreateContext())
{
var entities = await context.Set<EventEntity>()
.Where(e => e.AggregateId == id.Value)
.Select(e => new EventEntity {GlobalSequenceNumber = e.GlobalSequenceNumber})
.ToListAsync(cancellationToken)
.ConfigureAwait(false);

context.RemoveRange(entities);
var rowsAffected = await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

_log.Verbose(
"Deleted entity with ID '{0}' by deleting all of its {1} events",
id,
rowsAffected);
}
await using var context = _contextProvider.CreateContext();

var entities = await context.Set<EventEntity>()
.Where(e => e.AggregateId == id.Value)
.Select(e => new EventEntity {GlobalSequenceNumber = e.GlobalSequenceNumber})
.ToListAsync(cancellationToken);

context.RemoveRange(entities);
var rowsAffected = await context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);

_logger.LogTrace(
"Deleted entity with ID {Id} by deleting all of its {NumberOfEvents} events",
id,
rowsAffected);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using EventFlow.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace EventFlow.EntityFramework
{
public interface IEntityFrameworkConfiguration
{
void Apply(IServiceRegistration serviceRegistration);
void Apply(IServiceCollection serviceCollection);
}
}