From 828226a1483816ba0ada4da013b68af08e176389 Mon Sep 17 00:00:00 2001 From: Mads Larsen Date: Sun, 19 Jan 2025 21:14:37 +0100 Subject: [PATCH] v1: Entity Framework migration --- .DS_Store | Bin 0 -> 8196 bytes EventFlow.sln | 7 + Source/.DS_Store | Bin 0 -> 10244 bytes .../EntityFrameworkTestExtensions.cs | 3 +- .../EventFlow.EntityFramework.Tests.csproj | 14 +- .../InMemory/EfInMemoryEventStoreTests.cs | 17 ++- .../InMemory/EfInMemoryReadStoreTests.cs | 14 +- .../InMemory/EfInMemorySnapshotTests.cs | 15 +- .../InMemory/InMemoryDbContextProvider.cs | 7 +- .../Infrastructure/IndexingInMemoryTable.cs | 36 +++-- .../IndexingInMemoryTableFactory.cs | 7 +- .../Model/TestDbContext.cs | 2 +- .../Model/ThingyMessageReadModelEntity.cs | 8 +- .../Model/ThingyReadModelEntity.cs | 17 ++- .../MsSql/EfMsSqlEventStoreTests.cs | 19 ++- .../MsSql/EfMsSqlReadStoreIncludeTests.cs | 17 ++- .../MsSql/EfMsSqlReadStoreTests.cs | 16 +- .../MsSql/EfMsSqlSnapshotTests.cs | 17 ++- .../ReadModels/PersonReadModelEntity.cs | 12 +- .../PostgreSql/EfPostgreSqlEventStoreTests.cs | 19 ++- .../PostgreSql/EfPostgreSqlReadStoreTests.cs | 16 +- .../PostgreSql/EfPostgreSqlSnapshotTests.cs | 20 ++- .../SQLite/EfSqliteEventStoreTests.cs | 17 ++- .../SQLite/EfSqliteReadStoreTests.cs | 15 +- ...pshotTests.cs => EfSqliteSnapshotTests.cs} | 16 +- .../EntityFrameworkConfiguration.cs | 2 +- .../EventFlow.EntityFramework.csproj | 2 +- .../EntityFrameworkEventPersistence.cs | 6 +- .../EventStores/EventEntity.cs | 2 +- .../Extensions/DbContextExtensions.cs | 2 +- ...ionsEntityFrameworkEventStoreExtensions.cs | 35 ----- ...entFlowOptionsEntityFrameworkExtensions.cs | 139 +++++++++++++++++- ...tionsEntityFrameworkReadStoreExtensions.cs | 95 ------------ ...ptionsEntityFrameworkSnapshotExtensions.cs | 37 ----- .../EntityFrameworkReadModelStore.cs | 2 +- .../EntityFrameworkSnapshotPersistence.cs | 2 +- .../SnapshotStores/SnapshotEntity.cs | 2 +- 37 files changed, 348 insertions(+), 309 deletions(-) create mode 100644 .DS_Store create mode 100644 Source/.DS_Store rename Source/EventFlow.EntityFramework.Tests/SQLite/{EfInMemorySnapshotTests.cs => EfSqliteSnapshotTests.cs} (81%) delete mode 100644 Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkEventStoreExtensions.cs delete mode 100644 Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkReadStoreExtensions.cs delete mode 100644 Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkSnapshotExtensions.cs diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5b3ea83bccfa557b792fa998e40111aa9f14054d GIT binary patch literal 8196 zcmeHM!EVz)5S?vH>ktZ20jV57mbjLZmQaDXgfuCtR8px4Z~zpN#wu1^JJ?PGsw(9S z|G+PBDO6dvb# zq0H$!*MS0jq89Db4%%&?DMkUKfKk9GU=%P4{ErIYoz2C{c<-xG(;5Yg0yC)q|328L zjAe}@h4QBZjZ6W63%D%{`p5$$$JSWZI8rF7m{VmBLQ{oKF@&OH+-7rNS>s5dqLWZ` z5_)B!GZZ0L2hWz~B+3d+YZNdFTvUK__Z6A1SE-iB-|JMR7Z_>MIvrDY*9#6iUeJL( zKVnZ&*MG@^9?>;9M;+D&v`ZB*o4`6fo67$72kd>!)R@K=w^QsD>QX?5)FX#Nx`$o> zkNapN+*zkjxbl+zi!Z4;ma$u&V*p!+e2S@!>f)ZCV*b3qtkH?)?2re>5Nk&0rI>R^ zDdsIGp25Tn>`x2@9JK6-Pe&9beUVZ4IuV6Ce?KEu8c3bO)Z84S$+@q<2UgaH!W*V&=p$=H)D_=M-BjxSwJ^roIvf`%!6h9Yia@3?ZU{eu@DV6O2W8HnvXLLc?s^&M@lh=ly%9@3~Q2EdCI4^9z?2 zm#if#Z@q224~C7n9S@>PJABPo%^>hP=lyo)rRxk^g&W&}AGclK2_?bpIxus+jE>1!hYD zu~2PPE7)_^OObPJ8}%J37q%NIloT{F9S6#E960`mA^J8K*U_+tdM<}#HU4(=&fwnSq;3P``*fCs|f;!d#;u9EKGj^b@xB^qJ9+Yua zW{IJ+JMIVkIBd<>fwtP6ly)a&A}g~(Q4$?~fjmyCrma7F20R1%8Q``1B+XHXReLA5 zey`IOu13_xTE2_B3C`(4l&rR*qy;bTXfrsb|B-?kQJLoHDR5%!1KfdcLj8irp9PQe z`#lhEhEhcP0Z2WXl^umn9!Fg+;Cy*l9H8F=ZVKeW+o%@>%yU*u&ZiB81`xLKj>XL0 zzC$@XiTb6(p}6xJS$l_=B&dI3MVv=2O?j^nI;P053Ds6BYy43mD`&G(Veg8ZP5SXY2_o)Tm7_a z`o`a_ZWN}yO68Rr866uxcD!`Fbh7kwV?F6Ndd=QeT5oPX90(j zpH1RkGmJZ%;t;kwc;u%CVcbso^<*nE8Na>RNjZMe&0fkbK0 zI$C2FpAc<*E&m4G|I}&S|2i>Hr#=i7c`spv?tr_{#9ctNMbtNh(d|N9^v*19ncwEh z2gh}dpBR&~2z`!l)*9h1*a9o`7=ffDfk|2&3r$N&HGkUx0_JOlqv z2GrPGW3G;OQ;zrJz4iddBOF}#xq-Igf|G2=!^(C%zVLSZbsYR`g)JAcJK7QgL6O7um5ek8SdZXvNk!be~ sr.RegisterType(typeof(ThingyMessageLocator))) + .RegisterServices(sr => sr.AddTransient(typeof(ThingyMessageLocator))) .UseEntityFrameworkReadModel() .UseEntityFrameworkReadModel() .AddQueryHandlers( diff --git a/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj b/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj index 6f293aba1..efaad38f5 100644 --- a/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj +++ b/Source/EventFlow.EntityFramework.Tests/EventFlow.EntityFramework.Tests.csproj @@ -1,18 +1,18 @@  - netcoreapp3.1 + net8.0 False - - - + + + - - - + + + diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryEventStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryEventStoreTests.cs index ec2ededc8..81cbb4dfe 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryEventStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryEventStoreTests.cs @@ -20,12 +20,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 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 @@ -33,13 +33,16 @@ 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(Lifetime.Singleton) - .ConfigureForEventStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForEventStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryReadStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryReadStoreTests.cs index d786ea14d..11a6406c6 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryReadStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemoryReadStoreTests.cs @@ -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 @@ -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(Lifetime.Singleton) - .ConfigureForReadStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForReadStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemorySnapshotTests.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemorySnapshotTests.cs index 9636135ee..11c90c1bb 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemorySnapshotTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/EfInMemorySnapshotTests.cs @@ -20,11 +20,13 @@ // 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 @@ -32,13 +34,16 @@ 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(Lifetime.Singleton) - .ConfigureForSnapshotStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForSnapshotStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/InMemoryDbContextProvider.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/InMemoryDbContextProvider.cs index 59c3f8356..40e2d918d 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/InMemoryDbContextProvider.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/InMemoryDbContextProvider.cs @@ -20,6 +20,8 @@ // 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; @@ -27,14 +29,15 @@ namespace EventFlow.EntityFramework.Tests.InMemory { + [SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Only for tests")] public class InMemoryDbContextProvider : IDbContextProvider { private readonly DbContextOptions _options; - + public InMemoryDbContextProvider() { _options = new DbContextOptionsBuilder() - .UseInMemoryDatabase("EventFlowTest") + .UseInMemoryDatabase($"EventFlowTest-{Guid.NewGuid()}") .ReplaceService() .Options; } diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTable.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTable.cs index 9e8ceb864..935095b39 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTable.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTable.cs @@ -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; @@ -39,6 +40,12 @@ public class IndexingInMemoryTable : IInMemoryTable private readonly HashSet[] _indexes; private readonly IInMemoryTable _innerTable; + public IEnumerable 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; @@ -51,34 +58,39 @@ public IReadOnlyList SnapshotRows() return _innerTable.SnapshotRows(); } - public void Create(IUpdateEntry entry) - { + public void Create(IUpdateEntry entry, IDiagnosticsLogger 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 updateLogger) + { + _innerTable.Delete(entry, updateLogger); } - public void Delete(IUpdateEntry entry) + public void Update(IUpdateEntry entry, IDiagnosticsLogger updateLogger) { - _innerTable.Delete(entry); + _innerTable.Update(entry, updateLogger); } - public void Update(IUpdateEntry entry) + public InMemoryIntegerValueGenerator GetIntegerValueGenerator(IProperty property, IReadOnlyList tables) { - _innerTable.Update(entry); + return _innerTable.GetIntegerValueGenerator(property, tables); } - public InMemoryIntegerValueGenerator GetIntegerValueGenerator(IProperty property) + public void BumpValueGenerators(object[] row) { - return _innerTable.GetIntegerValueGenerator(property); + _innerTable.BumpValueGenerators(row); } private struct IndexEntry diff --git a/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTableFactory.cs b/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTableFactory.cs index 385bf1837..957bd0eb2 100644 --- a/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTableFactory.cs +++ b/Source/EventFlow.EntityFramework.Tests/InMemory/Infrastructure/IndexingInMemoryTableFactory.cs @@ -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; @@ -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() diff --git a/Source/EventFlow.EntityFramework.Tests/Model/TestDbContext.cs b/Source/EventFlow.EntityFramework.Tests/Model/TestDbContext.cs index edc551470..25b966af9 100644 --- a/Source/EventFlow.EntityFramework.Tests/Model/TestDbContext.cs +++ b/Source/EventFlow.EntityFramework.Tests/Model/TestDbContext.cs @@ -56,7 +56,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity() .Property(e => e.AggregateId) .ValueGeneratedOnAdd(); - + modelBuilder.Entity() .Property(e => e.AddressId) .ValueGeneratedNever(); diff --git a/Source/EventFlow.EntityFramework.Tests/Model/ThingyMessageReadModelEntity.cs b/Source/EventFlow.EntityFramework.Tests/Model/ThingyMessageReadModelEntity.cs index 4cb7a79c4..f28f4cf20 100644 --- a/Source/EventFlow.EntityFramework.Tests/Model/ThingyMessageReadModelEntity.cs +++ b/Source/EventFlow.EntityFramework.Tests/Model/ThingyMessageReadModelEntity.cs @@ -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; @@ -41,19 +43,21 @@ public class ThingyMessageReadModelEntity : IReadModel, public string Message { get; set; } - public void Apply(IReadModelContext context, IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { ThingyId = domainEvent.AggregateIdentity.Value; Message = domainEvent.AggregateEvent.ThingyMessage.Message; + return Task.CompletedTask; } - public void Apply(IReadModelContext context, IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, IDomainEvent 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() diff --git a/Source/EventFlow.EntityFramework.Tests/Model/ThingyReadModelEntity.cs b/Source/EventFlow.EntityFramework.Tests/Model/ThingyReadModelEntity.cs index 90673c8c5..f049f8374 100644 --- a/Source/EventFlow.EntityFramework.Tests/Model/ThingyReadModelEntity.cs +++ b/Source/EventFlow.EntityFramework.Tests/Model/ThingyReadModelEntity.cs @@ -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; @@ -42,22 +44,25 @@ public class ThingyReadModelEntity : IReadModel, [ConcurrencyCheck] public long Version { get; set; } - public void Apply(IReadModelContext context, - IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, + IDomainEvent domainEvent, CancellationToken cancellationToken) { context.MarkForDeletion(); + return Task.CompletedTask; } - public void Apply(IReadModelContext context, - IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, + IDomainEvent domainEvent, CancellationToken cancellationToken) { DomainErrorAfterFirstReceived = true; + return Task.CompletedTask; } - public void Apply(IReadModelContext context, - IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, + IDomainEvent domainEvent, CancellationToken cancellationToken) { PingsReceived++; + return Task.CompletedTask; } public Thingy ToThingy() diff --git a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlEventStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlEventStoreTests.cs index b5cf9b25e..0adf6d749 100644 --- a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlEventStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlEventStoreTests.cs @@ -20,14 +20,14 @@ // 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.Extensions; using EventFlow.TestHelpers; using EventFlow.TestHelpers.MsSql; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; namespace EventFlow.EntityFramework.Tests.MsSql @@ -37,22 +37,25 @@ public class EfMsSqlEventStoreTests : TestSuiteForEventStore { private IMsSqlDatabase _testDatabase; - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = MsSqlHelpz.CreateDatabase("eventflow"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForEventStoreTest() - .CreateResolver(); + .ConfigureForEventStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreIncludeTests.cs b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreIncludeTests.cs index 74b92cace..5ea41efd0 100644 --- a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreIncludeTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreIncludeTests.cs @@ -20,6 +20,7 @@ // 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.Threading; using System.Threading.Tasks; using EventFlow.Configuration; @@ -32,6 +33,7 @@ using EventFlow.TestHelpers; using EventFlow.TestHelpers.MsSql; using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; namespace EventFlow.EntityFramework.Tests.MsSql @@ -41,23 +43,26 @@ public class EfMsSqlReadStoreIncludeTests : IntegrationTest { private IMsSqlDatabase _testDatabase; - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = MsSqlHelpz.CreateDatabase("eventflow"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() .ConfigureForReadStoreIncludeTest() - .AddDefaults(typeof(EfMsSqlReadStoreIncludeTests).Assembly) - .CreateResolver(); + .AddDefaults(typeof(EfMsSqlReadStoreIncludeTests).Assembly); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } [Test] diff --git a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreTests.cs index b6eb90dfa..cd6720e47 100644 --- a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlReadStoreTests.cs @@ -28,6 +28,7 @@ using EventFlow.TestHelpers; using EventFlow.TestHelpers.MsSql; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; namespace EventFlow.EntityFramework.Tests.MsSql @@ -39,22 +40,25 @@ public class EfMsSqlReadStoreTests : TestSuiteForReadModelStore protected override Type ReadModelType => typeof(ThingyReadModelEntity); - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = MsSqlHelpz.CreateDatabase("eventflow"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForReadStoreTest() - .CreateResolver(); + .ConfigureForReadStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlSnapshotTests.cs b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlSnapshotTests.cs index aaabe9e54..c2a3a6aa3 100644 --- a/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlSnapshotTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/MsSql/EfMsSqlSnapshotTests.cs @@ -27,7 +27,9 @@ using EventFlow.TestHelpers; using EventFlow.TestHelpers.MsSql; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; +using System; namespace EventFlow.EntityFramework.Tests.MsSql { @@ -36,22 +38,25 @@ public class EfMsSqlSnapshotTests : TestSuiteForSnapshotStore { private IMsSqlDatabase _testDatabase; - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = MsSqlHelpz.CreateDatabase("eventflow-snapshots"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForSnapshotStoreTest() - .CreateResolver(); + .ConfigureForSnapshotStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/MsSql/IncludeTests/ReadModels/PersonReadModelEntity.cs b/Source/EventFlow.EntityFramework.Tests/MsSql/IncludeTests/ReadModels/PersonReadModelEntity.cs index 5a59fdc70..002cf892d 100644 --- a/Source/EventFlow.EntityFramework.Tests/MsSql/IncludeTests/ReadModels/PersonReadModelEntity.cs +++ b/Source/EventFlow.EntityFramework.Tests/MsSql/IncludeTests/ReadModels/PersonReadModelEntity.cs @@ -23,6 +23,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using EventFlow.Aggregates; using EventFlow.EntityFramework.Tests.MsSql.IncludeTests.Events; using EventFlow.ReadStores; @@ -43,14 +45,14 @@ public class PersonReadModelEntity : IReadModel, public virtual ICollection Addresses { get; set; } = new List(); - public void Apply(IReadModelContext context, - IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { Name = domainEvent.AggregateEvent.Name; + + return Task.CompletedTask; } - public void Apply(IReadModelContext context, - IDomainEvent domainEvent) + public Task ApplyAsync(IReadModelContext context, IDomainEvent domainEvent, CancellationToken cancellationToken) { var address = domainEvent.AggregateEvent.Address; Addresses.Add(new AddressReadModelEntity @@ -64,6 +66,8 @@ public void Apply(IReadModelContext context, }); NumberOfAddresses = Addresses.Count; + + return Task.CompletedTask; } public Person ToPerson() => diff --git a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlEventStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlEventStoreTests.cs index 7b01ec634..ea3aed036 100644 --- a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlEventStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlEventStoreTests.cs @@ -20,14 +20,14 @@ // 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.Extensions; using EventFlow.PostgreSql.TestsHelpers; using EventFlow.TestHelpers; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; namespace EventFlow.EntityFramework.Tests.PostgreSql @@ -37,22 +37,25 @@ public class EfPostgreSqlEventStoreTests : TestSuiteForEventStore { private IPostgreSqlDatabase _testDatabase; - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = PostgreSqlHelpz.CreateDatabase("eventflow"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForEventStoreTest() - .CreateResolver(); + .ConfigureForEventStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlReadStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlReadStoreTests.cs index e17ead3d3..3eee93820 100644 --- a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlReadStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlReadStoreTests.cs @@ -28,6 +28,7 @@ using EventFlow.PostgreSql.TestsHelpers; using EventFlow.TestHelpers; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; namespace EventFlow.EntityFramework.Tests.PostgreSql @@ -39,22 +40,25 @@ public class EfPostgreSqlReadStoreTests : TestSuiteForReadModelStore protected override Type ReadModelType => typeof(ThingyReadModelEntity); - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { _testDatabase = PostgreSqlHelpz.CreateDatabase("eventflow"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForReadStoreTest() - .CreateResolver(); + .ConfigureForReadStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlSnapshotTests.cs b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlSnapshotTests.cs index 17c011957..7c2491b41 100644 --- a/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlSnapshotTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/PostgreSql/EfPostgreSqlSnapshotTests.cs @@ -20,14 +20,15 @@ // 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 EventFlow.EntityFramework.Extensions; using EventFlow.EntityFramework.Tests.Model; using EventFlow.Extensions; using EventFlow.PostgreSql.TestsHelpers; using EventFlow.TestHelpers; using EventFlow.TestHelpers.Suites; +using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; +using System; namespace EventFlow.EntityFramework.Tests.PostgreSql { @@ -36,22 +37,25 @@ public class EfPostgreSqlSnapshotTests : TestSuiteForSnapshotStore { private IPostgreSqlDatabase _testDatabase; - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { - _testDatabase = PostgreSqlHelpz.CreateDatabase("eventflow-snapshots"); + _testDatabase = PostgreSqlHelpz.CreateDatabase("snapshots"); - return eventFlowOptions - .RegisterServices(sr => sr.Register(c => _testDatabase.ConnectionString)) + var resolver = eventFlowOptions + .RegisterServices(sr => sr.AddTransient(c => _testDatabase.ConnectionString)) .ConfigureEntityFramework(EntityFrameworkConfiguration.New) .AddDbContextProvider() - .ConfigureForSnapshotStoreTest() - .CreateResolver(); + .ConfigureForSnapshotStoreTest(); + + var serviceProvider = base.Configure(resolver); + + return serviceProvider; } [TearDown] public void TearDown() { - _testDatabase.DisposeSafe("Failed to delete database"); + _testDatabase.DisposeSafe(Logger, "Failed to delete database"); } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteEventStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteEventStoreTests.cs index 68212d2ec..a1cd8a2be 100644 --- a/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteEventStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteEventStoreTests.cs @@ -20,12 +20,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 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.SQLite @@ -33,13 +33,16 @@ namespace EventFlow.EntityFramework.Tests.SQLite [Category(Categories.Integration)] public class EfSqliteEventStoreTests : TestSuiteForEventStore { - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { - return eventFlowOptions + eventFlowOptions .ConfigureEntityFramework(EntityFrameworkConfiguration.New) - .AddDbContextProvider(Lifetime.Singleton) - .ConfigureForEventStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForEventStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteReadStoreTests.cs b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteReadStoreTests.cs index 3f2fb665f..07121f7af 100644 --- a/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteReadStoreTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteReadStoreTests.cs @@ -21,11 +21,11 @@ // 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.SQLite @@ -35,13 +35,16 @@ public class EfSqliteReadStoreTests : 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(Lifetime.Singleton) - .ConfigureForReadStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForReadStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework.Tests/SQLite/EfInMemorySnapshotTests.cs b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteSnapshotTests.cs similarity index 81% rename from Source/EventFlow.EntityFramework.Tests/SQLite/EfInMemorySnapshotTests.cs rename to Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteSnapshotTests.cs index 89cd8b13f..7ec907141 100644 --- a/Source/EventFlow.EntityFramework.Tests/SQLite/EfInMemorySnapshotTests.cs +++ b/Source/EventFlow.EntityFramework.Tests/SQLite/EfSqliteSnapshotTests.cs @@ -20,11 +20,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 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.SQLite @@ -32,13 +33,16 @@ namespace EventFlow.EntityFramework.Tests.SQLite [Category(Categories.Integration)] public class EfSqliteSnapshotTests : TestSuiteForSnapshotStore { - protected override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOptions) + protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions) { - return eventFlowOptions + eventFlowOptions .ConfigureEntityFramework(EntityFrameworkConfiguration.New) - .AddDbContextProvider(Lifetime.Singleton) - .ConfigureForSnapshotStoreTest() - .CreateResolver(); + .AddDbContextProvider(ServiceLifetime.Singleton) + .ConfigureForSnapshotStoreTest(); + + var serviceProvider = base.Configure(eventFlowOptions); + + return serviceProvider; } } } \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework/EntityFrameworkConfiguration.cs b/Source/EventFlow.EntityFramework/EntityFrameworkConfiguration.cs index a3c5de877..e3ed8a2df 100644 --- a/Source/EventFlow.EntityFramework/EntityFrameworkConfiguration.cs +++ b/Source/EventFlow.EntityFramework/EntityFrameworkConfiguration.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj b/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj index 9f653616e..cd664c651 100644 --- a/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj +++ b/Source/EventFlow.EntityFramework/EventFlow.EntityFramework.csproj @@ -8,7 +8,7 @@ EventFlow.EntityFramework Frank Ebersoll Rasmus Mikkelsen - Copyright (c) Rasmus Mikkelsen 2015 - 2022 + Copyright (c) Rasmus Mikkelsen 2015 - 2025 Entity Framework Core support for EventFlow CQRS ES event sourcing EF Entity Framework Core git diff --git a/Source/EventFlow.EntityFramework/EventStores/EntityFrameworkEventPersistence.cs b/Source/EventFlow.EntityFramework/EventStores/EntityFrameworkEventPersistence.cs index 4ea76c41a..e3c9db7b0 100644 --- a/Source/EventFlow.EntityFramework/EventStores/EntityFrameworkEventPersistence.cs +++ b/Source/EventFlow.EntityFramework/EventStores/EntityFrameworkEventPersistence.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -21,7 +21,6 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -35,10 +34,7 @@ namespace EventFlow.EntityFramework.EventStores; -[SuppressMessage("Code Fix", "Sc0023:Async Suffix")] -#pragma warning disable Wintellect011 public class EntityFrameworkEventPersistence : IEventPersistence -#pragma warning restore Wintellect011 where TDbContext : DbContext { private readonly IDbContextProvider _contextProvider; diff --git a/Source/EventFlow.EntityFramework/EventStores/EventEntity.cs b/Source/EventFlow.EntityFramework/EventStores/EventEntity.cs index f49451eea..b5c53e651 100644 --- a/Source/EventFlow.EntityFramework/EventStores/EventEntity.cs +++ b/Source/EventFlow.EntityFramework/EventStores/EventEntity.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/Source/EventFlow.EntityFramework/Extensions/DbContextExtensions.cs b/Source/EventFlow.EntityFramework/Extensions/DbContextExtensions.cs index 396b82882..06186d0a8 100644 --- a/Source/EventFlow.EntityFramework/Extensions/DbContextExtensions.cs +++ b/Source/EventFlow.EntityFramework/Extensions/DbContextExtensions.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkEventStoreExtensions.cs b/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkEventStoreExtensions.cs deleted file mode 100644 index aee6748af..000000000 --- a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkEventStoreExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015-2024 Rasmus Mikkelsen -// https://github.com/eventflow/EventFlow -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// 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.EntityFramework.EventStores; -using EventFlow.Extensions; -using Microsoft.EntityFrameworkCore; - -namespace EventFlow.EntityFramework.Extensions; - -public static class EventFlowOptionsEntityFrameworkEventStoreExtensions -{ - public static IEventFlowOptions UseEntityFrameworkEventStore(this IEventFlowOptions eventFlowOptions) - where TDbContext : DbContext - { - return eventFlowOptions.UseEventPersistence>(); - } -} diff --git a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkExtensions.cs b/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkExtensions.cs index 34bc429bb..3b7e58934 100644 --- a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkExtensions.cs +++ b/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkExtensions.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -19,8 +19,14 @@ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // 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.EntityFramework.EventStores; +using EventFlow.EntityFramework.ReadStores; +using EventFlow.EntityFramework.ReadStores.Configuration; +using EventFlow.EntityFramework.SnapshotStores; using EventFlow.Extensions; +using EventFlow.ReadStores; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -29,19 +35,130 @@ namespace EventFlow.EntityFramework.Extensions; public static class EventFlowOptionsEntityFrameworkExtensions { - public static IEventFlowOptions AddDbContextProvider(this IEventFlowOptions eventFlowOptions, - ServiceLifetime serviceLifetime = ServiceLifetime.Transient) + public static IEventFlowOptions UseEntityFrameworkReadModel( + this IEventFlowOptions eventFlowOptions) + where TDbContext : DbContext + where TReadModel : class, IReadModel, new() + { + return eventFlowOptions + .RegisterServices(f => + { + f.TryAddTransient, + EntityFrameworkReadModelStore>(); + f.TryAddSingleton>(_ => + new EntityFrameworkReadModelConfiguration()); + f.TryAddTransient>(r => + r.GetRequiredService>()); + }) + .UseReadStoreFor, TReadModel>(); + } + + /// + /// Configures the read model. Can be used for eager loading of related data by appending .Include(..) / .ThenInclude(..) statements. + /// + /// The read model's entity type + /// The database context type + /// The read model locator type + /// + /// Function to configure eager loading of related data by appending .Include(..) / .ThenInclude(..) statements. + /// Avoid navigation properties if you create read models for both, the parent entity and the child entity. Otherwise there is a risk of a ordering problem when saving aggregates and updating read modules independently (FOREIGN-KEY constraint) + public static IEventFlowOptions UseEntityFrameworkReadModel( + this IEventFlowOptions eventFlowOptions, + Func, IApplyQueryableConfiguration> configure) + where TDbContext : DbContext + where TReadModel : class, IReadModel, new() + where TReadModelLocator : IReadModelLocator + { + return eventFlowOptions + .RegisterServices(f => + { + f.TryAddTransient, + EntityFrameworkReadModelStore>(); + f.TryAddSingleton(_ => + { + var readModelConfig = new EntityFrameworkReadModelConfiguration(); + return configure != null + ? configure(readModelConfig) + : readModelConfig; + }); + f.TryAddTransient>(r => + r.GetRequiredService>()); + }) + .UseReadStoreFor, TReadModel, TReadModelLocator>(); + } + + public static IEventFlowOptions UseEntityFrameworkReadModel( + this IEventFlowOptions eventFlowOptions) + where TDbContext : DbContext + where TReadModel : class, IReadModel, new() + where TReadModelLocator : IReadModelLocator + { + return eventFlowOptions + .RegisterServices(f => + { + f.TryAddTransient, + EntityFrameworkReadModelStore>(); + f.TryAddSingleton>(_ => + new EntityFrameworkReadModelConfiguration()); + f.TryAddTransient>(r => + r.GetRequiredService>()); + }) + .UseReadStoreFor, TReadModel, TReadModelLocator>(); + } + + /// + /// Configures the read model. Can be used for eager loading of related data by appending .Include(..) / .ThenInclude(..) statements. + /// + /// The read model's entity type + /// The database context type + /// + /// Function to configure eager loading of related data by appending .Include(..) / .ThenInclude(..) statements. + /// Avoid navigation properties if you create read models for both, the parent entity and the child entity. Otherwise there is a risk of a ordering problem when saving aggregates and updating read modules independently (FOREIGN-KEY constraint) + public static IEventFlowOptions UseEntityFrameworkReadModel( + this IEventFlowOptions eventFlowOptions, + Func, IApplyQueryableConfiguration> configure) + where TDbContext : DbContext + where TReadModel : class, IReadModel, new() + { + return eventFlowOptions + .RegisterServices(f => + { + f.TryAddTransient, + EntityFrameworkReadModelStore>(); + f.TryAddSingleton(_ => + { + var readModelConfig = new EntityFrameworkReadModelConfiguration(); + return configure != null + ? configure(readModelConfig) + : readModelConfig; + }); + f.TryAddTransient>(r => + r.GetRequiredService>()); + }) + .UseReadStoreFor, TReadModel>(); + } + + public static IEventFlowOptions UseEntityFrameworkSnapshotStore(this IEventFlowOptions eventFlowOptions) + where TDbContext : DbContext + { + return eventFlowOptions + .UseSnapshotPersistence>(ServiceLifetime.Transient); + } + + public static IEventFlowOptions AddDbContextProvider( + this IEventFlowOptions eventFlowOptions, + ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where TContextProvider : class, IDbContextProvider where TDbContext : DbContext { return eventFlowOptions.RegisterServices(s => - s.Replace(ServiceDescriptor.Describe(typeof(IDbContextProvider), - typeof(TContextProvider), - serviceLifetime))); + s.Replace(ServiceDescriptor.Describe(typeof(IDbContextProvider), + typeof(TContextProvider), + serviceLifetime))); } public static IEventFlowOptions ConfigureEntityFramework(this IEventFlowOptions eventFlowOptions, - IEntityFrameworkConfiguration configuration) + IEntityFrameworkConfiguration configuration) { if (configuration == null) { @@ -50,4 +167,10 @@ public static IEventFlowOptions ConfigureEntityFramework(this IEventFlowOptions return eventFlowOptions.RegisterServices(configuration.Apply); } -} + + public static IEventFlowOptions UseEntityFrameworkEventStore(this IEventFlowOptions eventFlowOptions) + where TDbContext : DbContext + { + return eventFlowOptions.UseEventPersistence>(); + } +} \ No newline at end of file diff --git a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkReadStoreExtensions.cs b/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkReadStoreExtensions.cs deleted file mode 100644 index aa764aec2..000000000 --- a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkReadStoreExtensions.cs +++ /dev/null @@ -1,95 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015-2024 Rasmus Mikkelsen -// https://github.com/eventflow/EventFlow -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// 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.EntityFramework.ReadStores; -using EventFlow.EntityFramework.ReadStores.Configuration; -using EventFlow.Extensions; -using EventFlow.ReadStores; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; - -namespace EventFlow.EntityFramework.Extensions; - -public static class EventFlowOptionsEntityFrameworkReadStoreExtensions -{ - public static IEventFlowOptions UseEntityFrameworkReadModel(this IEventFlowOptions eventFlowOptions) - where TDbContext : DbContext - where TReadModel : class, IReadModel, new() - { - return eventFlowOptions.ApplyEntityFrameworkReadModelOptions(new EntityFrameworkReadModelConfiguration()) - .UseReadStoreFor, TReadModel>(); - } - - public static IEventFlowOptions UseEntityFrameworkReadModel(this IEventFlowOptions eventFlowOptions, - Func, - IApplyQueryableConfiguration> configure) - where TDbContext : DbContext - where TReadModel : class, IReadModel, new() - { - var readModelConfig = new EntityFrameworkReadModelConfiguration(); - configure(readModelConfig); - - return eventFlowOptions.ApplyEntityFrameworkReadModelOptions(readModelConfig) - .UseReadStoreFor, TReadModel>(); - } - - public static IEventFlowOptions UseEntityFrameworkReadModel(this IEventFlowOptions eventFlowOptions, - Func, IApplyQueryableConfiguration> configure) - where TDbContext : DbContext - where TReadModel : class, IReadModel, new() - where TReadModelLocator : IReadModelLocator - { - var readModelConfig = new EntityFrameworkReadModelConfiguration(); - configure(readModelConfig); - - return eventFlowOptions.ApplyEntityFrameworkReadModelOptions(readModelConfig) - .UseReadStoreFor, TReadModel, TReadModelLocator>(); - } - - public static IEventFlowOptions UseEntityFrameworkReadModel(this IEventFlowOptions eventFlowOptions) - where TDbContext : DbContext - where TReadModel : class, IReadModel, new() - where TReadModelLocator : IReadModelLocator - { - return eventFlowOptions.ApplyEntityFrameworkReadModelOptions(new EntityFrameworkReadModelConfiguration()) - .UseReadStoreFor, TReadModel, TReadModelLocator>(); - } - - private static IEventFlowOptions ApplyEntityFrameworkReadModelOptions(this IEventFlowOptions eventFlowOptions, - EntityFrameworkReadModelConfiguration config) - where TDbContext : DbContext - where TReadModel : class, IReadModel, new() - { - return eventFlowOptions - .RegisterServices(f => - { - f.TryAddTransient, - EntityFrameworkReadModelStore>(); - - f.TryAddSingleton>(_ => config); - - f.TryAddTransient>(r => - r.GetRequiredService>()); - }); - } -} diff --git a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkSnapshotExtensions.cs b/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkSnapshotExtensions.cs deleted file mode 100644 index 4ffdabb91..000000000 --- a/Source/EventFlow.EntityFramework/Extensions/EventFlowOptionsEntityFrameworkSnapshotExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015-2024 Rasmus Mikkelsen -// https://github.com/eventflow/EventFlow -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// 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.EntityFramework.SnapshotStores; -using EventFlow.Extensions; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; - -namespace EventFlow.EntityFramework.Extensions; - -public static class EventFlowOptionsEntityFrameworkSnapshotExtensions -{ - public static IEventFlowOptions UseEntityFrameworkSnapshotStore(this IEventFlowOptions eventFlowOptions) - where TDbContext : DbContext - { - return eventFlowOptions - .UseSnapshotPersistence>(ServiceLifetime.Transient); - } -} diff --git a/Source/EventFlow.EntityFramework/ReadStores/EntityFrameworkReadModelStore.cs b/Source/EventFlow.EntityFramework/ReadStores/EntityFrameworkReadModelStore.cs index 62a9da952..6d51df7bd 100644 --- a/Source/EventFlow.EntityFramework/ReadStores/EntityFrameworkReadModelStore.cs +++ b/Source/EventFlow.EntityFramework/ReadStores/EntityFrameworkReadModelStore.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/Source/EventFlow.EntityFramework/SnapshotStores/EntityFrameworkSnapshotPersistence.cs b/Source/EventFlow.EntityFramework/SnapshotStores/EntityFrameworkSnapshotPersistence.cs index 1d0148ce9..6773d83df 100644 --- a/Source/EventFlow.EntityFramework/SnapshotStores/EntityFrameworkSnapshotPersistence.cs +++ b/Source/EventFlow.EntityFramework/SnapshotStores/EntityFrameworkSnapshotPersistence.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/Source/EventFlow.EntityFramework/SnapshotStores/SnapshotEntity.cs b/Source/EventFlow.EntityFramework/SnapshotStores/SnapshotEntity.cs index 47155a3a6..d6e1f3941 100644 --- a/Source/EventFlow.EntityFramework/SnapshotStores/SnapshotEntity.cs +++ b/Source/EventFlow.EntityFramework/SnapshotStores/SnapshotEntity.cs @@ -1,6 +1,6 @@ // The MIT License (MIT) // -// Copyright (c) 2015-2024 Rasmus Mikkelsen +// Copyright (c) 2015-2025 Rasmus Mikkelsen // https://github.com/eventflow/EventFlow // // Permission is hereby granted, free of charge, to any person obtaining a copy of