Skip to content

Commit

Permalink
v1: Entity Framework migration
Browse files Browse the repository at this point in the history
  • Loading branch information
MMonrad committed Jan 19, 2025
1 parent bc01a46 commit 18911ca
Show file tree
Hide file tree
Showing 37 changed files with 317 additions and 191 deletions.
Binary file added .DS_Store
Binary file not shown.
7 changes: 7 additions & 0 deletions EventFlow.sln
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EntityFramework", "EntityFr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.EntityFramework", "Source\EventFlow.EntityFramework\EventFlow.EntityFramework.csproj", "{ED4AA905-A208-4E67-8B40-CC8E1B8440B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventFlow.EntityFramework.Tests", "Source\EventFlow.EntityFramework.Tests\EventFlow.EntityFramework.Tests.csproj", "{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -153,6 +155,10 @@ Global
{ED4AA905-A208-4E67-8B40-CC8E1B8440B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED4AA905-A208-4E67-8B40-CC8E1B8440B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED4AA905-A208-4E67-8B40-CC8E1B8440B8}.Release|Any CPU.Build.0 = Release|Any CPU
{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -185,6 +191,7 @@ Global
{8FAC191C-340D-47C6-B8AE-3D57783749C4} = {74EFCDE2-CB0F-49B1-9CEC-BE748EB1FBF7}
{21A29AA0-EF82-4717-89CE-729257C05C7D} = {5EE323DE-E69B-451A-8AC3-22DD6A004FBA}
{ED4AA905-A208-4E67-8B40-CC8E1B8440B8} = {21A29AA0-EF82-4717-89CE-729257C05C7D}
{02B1E8B4-CC53-4BAB-BC2C-AD0B06760AE2} = {21A29AA0-EF82-4717-89CE-729257C05C7D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {17607E2C-4E8E-45A2-85BD-0A5808E1C0F3}
Expand Down
Binary file added Source/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using EventFlow.EntityFramework.Tests.MsSql.IncludeTests.ReadModels;
using EventFlow.Extensions;
using EventFlow.TestHelpers.Aggregates.Entities;
using Microsoft.Extensions.DependencyInjection;

namespace EventFlow.EntityFramework.Tests
{
Expand All @@ -46,7 +47,7 @@ public static IEventFlowOptions ConfigureForSnapshotStoreTest(this IEventFlowOpt
public static IEventFlowOptions ConfigureForReadStoreTest(this IEventFlowOptions options)
{
return options
.RegisterServices(sr => sr.RegisterType(typeof(ThingyMessageLocator)))
.RegisterServices(sr => sr.AddTransient(typeof(ThingyMessageLocator)))
.UseEntityFrameworkReadModel<ThingyReadModelEntity, TestDbContext>()
.UseEntityFrameworkReadModel<ThingyMessageReadModelEntity, TestDbContext, ThingyMessageLocator>()
.AddQueryHandlers(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>False</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.11" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="Npgsql" Version="4.1.14" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="Npgsql" Version="8.0.6" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,29 @@
// 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 System.Threading.Tasks;
using EventFlow.Configuration;
using System;
using EventFlow.EntityFramework.Extensions;
using EventFlow.EntityFramework.Tests.Model;
using EventFlow.TestHelpers;
using EventFlow.TestHelpers.Suites;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;

namespace EventFlow.EntityFramework.Tests.InMemory
{
[Category(Categories.Integration)]
public class EfInMemoryEventStoreTests : TestSuiteForEventStore
{
protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions)
{
return eventFlowOptions
eventFlowOptions
.ConfigureEntityFramework(EntityFrameworkConfiguration.New)
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(Lifetime.Singleton)
.ConfigureForEventStoreTest()
.CreateResolver();
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(ServiceLifetime.Singleton)
.ConfigureForEventStoreTest();

var serviceProvider = base.Configure(eventFlowOptions);

return serviceProvider;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using EventFlow.EntityFramework.Tests.Model;
using EventFlow.TestHelpers;
using EventFlow.TestHelpers.Suites;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;

namespace EventFlow.EntityFramework.Tests.InMemory
Expand All @@ -35,13 +36,16 @@ public class EfInMemoryReadStoreTests : TestSuiteForReadModelStore
{
protected override Type ReadModelType => typeof(ThingyReadModelEntity);

protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions)
{
return eventFlowOptions
eventFlowOptions
.ConfigureEntityFramework(EntityFrameworkConfiguration.New)
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(Lifetime.Singleton)
.ConfigureForReadStoreTest()
.CreateResolver();
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(ServiceLifetime.Singleton)
.ConfigureForReadStoreTest();

var serviceProvider = base.Configure(eventFlowOptions);

return serviceProvider;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,30 @@
// 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 System;
using EventFlow.Configuration;
using EventFlow.EntityFramework.Extensions;
using EventFlow.EntityFramework.Tests.Model;
using EventFlow.TestHelpers;
using EventFlow.TestHelpers.Suites;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;

namespace EventFlow.EntityFramework.Tests.InMemory
{
[Category(Categories.Integration)]
public class EfInMemorySnapshotTests : TestSuiteForSnapshotStore
{
protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions)
protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions)
{
return eventFlowOptions
eventFlowOptions
.ConfigureEntityFramework(EntityFrameworkConfiguration.New)
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(Lifetime.Singleton)
.ConfigureForSnapshotStoreTest()
.CreateResolver();
.AddDbContextProvider<TestDbContext, InMemoryDbContextProvider>(ServiceLifetime.Singleton)
.ConfigureForSnapshotStoreTest();

var serviceProvider = base.Configure(eventFlowOptions);

return serviceProvider;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,24 @@
// 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 System;
using System.Diagnostics.CodeAnalysis;
using EventFlow.EntityFramework.Tests.InMemory.Infrastructure;
using EventFlow.EntityFramework.Tests.Model;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;

namespace EventFlow.EntityFramework.Tests.InMemory
{
[SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Only for tests")]
public class InMemoryDbContextProvider : IDbContextProvider<TestDbContext>
{
private readonly DbContextOptions<TestDbContext> _options;

public InMemoryDbContextProvider()
{
_options = new DbContextOptionsBuilder<TestDbContext>()
.UseInMemoryDatabase("EventFlowTest")
.UseInMemoryDatabase($"EventFlowTest-{Guid.NewGuid()}")
.ReplaceService<IInMemoryTableFactory, IndexingInMemoryTableFactory>()
.Options;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
using Microsoft.EntityFrameworkCore.InMemory.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
Expand All @@ -39,6 +40,12 @@ public class IndexingInMemoryTable : IInMemoryTable
private readonly HashSet<IndexEntry>[] _indexes;
private readonly IInMemoryTable _innerTable;

public IEnumerable<object[]> Rows => _innerTable.Rows;

public IInMemoryTable BaseTable => _innerTable;

public IEntityType EntityType => throw new InvalidOperationException("Property deprecated in newer versions so not used anymore.");

public IndexingInMemoryTable(IInMemoryTable innerTable, IIndex[] indexDefinitions)
{
_innerTable = innerTable;
Expand All @@ -51,34 +58,39 @@ public IReadOnlyList<object[]> SnapshotRows()
return _innerTable.SnapshotRows();
}

public void Create(IUpdateEntry entry)
{
public void Create(IUpdateEntry entry, IDiagnosticsLogger<DbLoggerCategory.Update> updateLogger)
{
var indexEntries = _indexDefinitions
.Select(d => d.Properties.Select(entry.GetCurrentValue).ToArray())
.Select(values => new IndexEntry(values))
.ToArray();

if (indexEntries.Select((item, i) => _indexes[i].Contains(item)).Any(contains => contains))
throw new DbUpdateException("Error while updating.", new Exception("Unique constraint violated."));

_innerTable.Create(entry, updateLogger);

_ = indexEntries.Select((item, i) => _indexes[i].Add(item)).ToArray();
}

_innerTable.Create(entry);

indexEntries.Select((item, i) => _indexes[i].Add(item)).ToArray();
public void Delete(IUpdateEntry entry, IDiagnosticsLogger<DbLoggerCategory.Update> updateLogger)
{
_innerTable.Delete(entry, updateLogger);
}

public void Delete(IUpdateEntry entry)
public void Update(IUpdateEntry entry, IDiagnosticsLogger<DbLoggerCategory.Update> updateLogger)
{
_innerTable.Delete(entry);
_innerTable.Update(entry, updateLogger);
}

public void Update(IUpdateEntry entry)
public InMemoryIntegerValueGenerator<TProperty> GetIntegerValueGenerator<TProperty>(IProperty property, IReadOnlyList<IInMemoryTable> tables)
{
_innerTable.Update(entry);
return _innerTable.GetIntegerValueGenerator<TProperty>(property, tables);
}

public InMemoryIntegerValueGenerator<TProperty> GetIntegerValueGenerator<TProperty>(IProperty property)
public void BumpValueGenerators(object[] row)
{
return _innerTable.GetIntegerValueGenerator<TProperty>(property);
_innerTable.BumpValueGenerators(row);
}

private struct IndexEntry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

using System.Linq;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.InMemory.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
using Microsoft.EntityFrameworkCore.Metadata;

Expand All @@ -30,13 +31,13 @@ namespace EventFlow.EntityFramework.Tests.InMemory.Infrastructure
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Only for test")]
public class IndexingInMemoryTableFactory : InMemoryTableFactory
{
public IndexingInMemoryTableFactory(ILoggingOptions loggingOptions) : base(loggingOptions)
public IndexingInMemoryTableFactory(ILoggingOptions loggingOptions, IInMemorySingletonOptions option) : base(loggingOptions, option)
{
}

public override IInMemoryTable Create(IEntityType entityType)
public override IInMemoryTable Create(IEntityType entityType, IInMemoryTable baseTable)
{
var innerTable = base.Create(entityType);
var innerTable = base.Create(entityType, baseTable);
var uniqueIndexes = entityType.GetIndexes().Where(i => i.IsUnique).ToArray();

return uniqueIndexes.Any()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<PersonReadModelEntity>()
.Property(e => e.AggregateId)
.ValueGeneratedOnAdd();

modelBuilder.Entity<AddressReadModelEntity>()
.Property(e => e.AddressId)
.ValueGeneratedNever();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using EventFlow.Aggregates;
using EventFlow.ReadStores;
using EventFlow.TestHelpers.Aggregates;
Expand All @@ -41,19 +43,21 @@ public class ThingyMessageReadModelEntity : IReadModel,

public string Message { get; set; }

public void Apply(IReadModelContext context, IDomainEvent<ThingyAggregate, ThingyId, ThingyMessageAddedEvent> domainEvent)
public Task ApplyAsync(IReadModelContext context, IDomainEvent<ThingyAggregate, ThingyId, ThingyMessageAddedEvent> domainEvent, CancellationToken cancellationToken)
{
ThingyId = domainEvent.AggregateIdentity.Value;
Message = domainEvent.AggregateEvent.ThingyMessage.Message;
return Task.CompletedTask;
}

public void Apply(IReadModelContext context, IDomainEvent<ThingyAggregate, ThingyId, ThingyMessageHistoryAddedEvent> domainEvent)
public Task ApplyAsync(IReadModelContext context, IDomainEvent<ThingyAggregate, ThingyId, ThingyMessageHistoryAddedEvent> domainEvent, CancellationToken cancellationToken)
{
ThingyId = domainEvent.AggregateIdentity.Value;

var messageId = new ThingyMessageId(context.ReadModelId);
var thingyMessage = domainEvent.AggregateEvent.ThingyMessages.Single(m => m.Id == messageId);
Message = thingyMessage.Message;
return Task.CompletedTask;
}

public ThingyMessage ToThingyMessage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
using EventFlow.Aggregates;
using EventFlow.ReadStores;
using EventFlow.TestHelpers.Aggregates;
Expand All @@ -42,22 +44,25 @@ public class ThingyReadModelEntity : IReadModel,
[ConcurrencyCheck]
public long Version { get; set; }

public void Apply(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyDeletedEvent> domainEvent)
public Task ApplyAsync(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyDeletedEvent> domainEvent, CancellationToken cancellationToken)
{
context.MarkForDeletion();
return Task.CompletedTask;
}

public void Apply(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyDomainErrorAfterFirstEvent> domainEvent)
public Task ApplyAsync(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyDomainErrorAfterFirstEvent> domainEvent, CancellationToken cancellationToken)
{
DomainErrorAfterFirstReceived = true;
return Task.CompletedTask;
}

public void Apply(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyPingEvent> domainEvent)
public Task ApplyAsync(IReadModelContext context,
IDomainEvent<ThingyAggregate, ThingyId, ThingyPingEvent> domainEvent, CancellationToken cancellationToken)
{
PingsReceived++;
return Task.CompletedTask;
}

public Thingy ToThingy()
Expand Down
Loading

0 comments on commit 18911ca

Please sign in to comment.