Skip to content

Commit b03967c

Browse files
authored
Merge pull request #897 from eventflow/support-multiple-sql-databases
Support multiple SQL databases for read models
2 parents 16050ab + 414760a commit b03967c

29 files changed

+557
-147
lines changed

MIGRATION_GUIDE.md

+31
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,37 @@ Here is the general motivation for introducing breaking changes to EventFlow.
2020
- Add obviously missing async/await on critical methods
2121
- Remove non-async methods wrapper methods
2222

23+
## Notable new features in 1.x
24+
25+
While the main focus of 1.x is to bring EventFlow up to speed with the latest
26+
standards, there some changes/features that has been added as well. Features
27+
that wasn't possible to add before as introducing them would cause breaking changes.
28+
29+
- **Multiple MSSQL connection strings:** Its now possible to have read models
30+
outside the main database by adding a `[SqlReadModelConnectionStringName]`
31+
attribute to the read models. The named connection string is then used for
32+
that read model. To configure the named connection strings, provide them
33+
during the initial configuration.
34+
35+
```csharp
36+
MsSqlConfiguration.New
37+
.SetConnectionString(/* events connection string */)
38+
.SetConnectionString("my-awesome-read-model", /* alternative connection string */)
39+
```
40+
41+
If the connection string is not known at initialization, provide your own instance
42+
of the `IMsSqlConfiguration` which now has a new method.
43+
44+
```csharp
45+
Task<string> GetConnectionStringAsync(
46+
Label label,
47+
string name,
48+
CancellationToken cancellationToken);
49+
```
50+
51+
This allows for connection strings to be fetched runtime from external sources.
52+
53+
2354
## Data in event stores
2455

2556
Upgrading EventFlow should **never** break existing data in event stores, not even

RELEASE_NOTES.md

+26-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
11
### New in 1.0 alpha (not released yet)
22

3+
**IMPORTANT:** Major API breaking changes *might* occur between 1.0 pre-releases. As breaking
4+
API changes will need to be tested and verified before the final 1.0 release.
5+
36
Read the complete migration guide to get the full list of changes as well
47
as recommendations on how to do the migration.
58

69
https://github.com/eventflow/EventFlow/blob/develop-v1/MIGRATION_GUIDE.md
710

11+
* New/breaking: Replace internal IoC implementation with `Microsoft.Extensions.DependencyInjection`
12+
* New/breaking: Replace internal logging implementation with `Microsoft.Extensions.Logging`
13+
* New/breaking: SQL read models now support different connection strings using the
14+
`[SqlReadModelConnectionStringName]` attribute. To allow executing queries using different
15+
connection strings, all methods on `IMsSqlConnection` and `ISqlConnection` now have an
16+
additional argument, `string connectionStringName` to signify which connection string
17+
should be used for the query
18+
* New/breaking: SQL connection strings are now fetched from the
19+
`SqlConfiguration<T>.GetConnectionStringAsync(...)` instead of a property, allowing more
20+
control of the connection string used at runtime
21+
* New: Its now possible to change the execution timeout for database migrations using the
22+
`SetUpgradeExecutionTimeout(...)` on the SQL configuration
23+
* Breaking: Removed the following dead and/or confusion MSSQL attributes. The real ones
24+
are named the same, with with `Sql...` instead of `MsSql...`
25+
- `MsSqlReadModelIdentityColumn`
26+
- `MsSqlReadModelIgnoreColumn`
27+
- `MsSqlReadModelVersionColumn`
28+
* Breaking: Methods on `IMsSqlDatabaseMigrator` and `ISqlDatabaseMigrator` have been
29+
made async and have an extra `CancellationToken` argument
830
* Breaking: Remove support for .NET Framework and consolidate on .NET Core LTS versions
9-
* Breaking: Replace internal IoC implementation with `Microsoft.Extensions.DependencyInjection`
10-
* Breaking: Replace internal logging implementation with `Microsoft.Extensions.Logging`
1131
* Breaking: Replace internal in-memory caching with `Microsoft.Extensions.Caching.Memory`
12-
* Breaking: Remove `IAmAsyncReadModelFor` and made `IAmReadModelFor` async
32+
* Breaking: Removed `IAmAsyncReadModelFor` and made `IAmReadModelFor` async
1333
* Breaking: Removed `EventFlow.Core.AsyncHelper` as well as all async wrapper methods
14-
that used it.
34+
that used it
1535
- `IAggregateStore.Load`
1636
- `IAggregateStore.Store`
1737
- `IAggregateStore.Update`
@@ -22,6 +42,8 @@ https://github.com/eventflow/EventFlow/blob/develop-v1/MIGRATION_GUIDE.md
2242
- `IQueryProcessor.Process`
2343
- `IReadModelPopulator.Populate`
2444
- `IReadModelPopulator.Purge`
45+
* Version of 0.x included: `0.83.4713`. 0.x changes are merged to 1.x at regular
46+
intervals, but might be one or two releases behind
2547

2648

2749
### New in 0.83.4713 (released 2021-09-07)

Source/EventFlow.MsSql.Tests/Extensions/MsSqlDatabaseExtensions.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ namespace EventFlow.MsSql.Tests.Extensions
3030
{
3131
public static class MsSqlDatabaseExtensions
3232
{
33-
public static IReadOnlyCollection<T> Query<T>(this IMsSqlDatabase database, string sql)
33+
public static IReadOnlyCollection<T> Query<T>(
34+
this IMsSqlDatabase database,
35+
string sql,
36+
object param = null)
3437
{
35-
return database.WithConnection<IReadOnlyCollection<T>>(c => c.Query<T>(sql).ToList());
38+
return database.WithConnection<IReadOnlyCollection<T>>(c => c.Query<T>(sql, param).ToList());
3639
}
3740

3841
public static int Execute(this IMsSqlDatabase database, string sql, object param)

Source/EventFlow.MsSql.Tests/IntegrationTests/EventStores/MsSqlEventStoreTests.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323

2424
using System;
25+
using System.Threading;
2526
using EventFlow.MsSql.EventStores;
2627
using EventFlow.MsSql.Extensions;
2728
using EventFlow.TestHelpers;
@@ -48,8 +49,11 @@ protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions
4849
var serviceProvider = base.Configure(eventFlowOptions);
4950

5051
var databaseMigrator = serviceProvider.GetRequiredService<IMsSqlDatabaseMigrator>();
51-
EventFlowEventStoresMsSql.MigrateDatabase(databaseMigrator);
52-
databaseMigrator.MigrateDatabaseUsingEmbeddedScripts(GetType().Assembly);
52+
EventFlowEventStoresMsSql.MigrateDatabaseAsync(databaseMigrator, CancellationToken.None).Wait();
53+
databaseMigrator.MigrateDatabaseUsingEmbeddedScriptsAsync(
54+
GetType().Assembly,
55+
null, /* TODO */
56+
CancellationToken.None).Wait();
5357

5458
return serviceProvider;
5559
}
@@ -60,4 +64,4 @@ public void TearDown()
6064
_testDatabase.Dispose();
6165
}
6266
}
63-
}
67+
}

Source/EventFlow.MsSql.Tests/IntegrationTests/ReadStores/MsSqlReadModelStoreTests.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323

2424
using System;
25+
using System.Threading;
2526
using EventFlow.Extensions;
2627
using EventFlow.MsSql.EventStores;
2728
using EventFlow.MsSql.Extensions;
@@ -60,8 +61,11 @@ protected override IServiceProvider Configure(IEventFlowOptions eventFlowOptions
6061
var serviceProvider = base.Configure(eventFlowOptions);
6162

6263
var databaseMigrator = serviceProvider.GetRequiredService<IMsSqlDatabaseMigrator>();
63-
EventFlowEventStoresMsSql.MigrateDatabase(databaseMigrator);
64-
databaseMigrator.MigrateDatabaseUsingEmbeddedScripts(GetType().Assembly);
64+
EventFlowEventStoresMsSql.MigrateDatabaseAsync(databaseMigrator, CancellationToken.None).Wait();
65+
databaseMigrator.MigrateDatabaseUsingEmbeddedScriptsAsync(
66+
GetType().Assembly,
67+
null /* TODO */,
68+
CancellationToken.None).Wait();
6569

6670
return serviceProvider;
6771
}

Source/EventFlow.MsSql.Tests/IntegrationTests/ReadStores/QueryHandlers/MsSqlThingyGetMessagesQueryHandler.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using EventFlow.Core;
2929
using EventFlow.MsSql.Tests.IntegrationTests.ReadStores.ReadModels;
3030
using EventFlow.Queries;
31+
using EventFlow.Sql.Extensions;
3132
using EventFlow.TestHelpers.Aggregates.Entities;
3233
using EventFlow.TestHelpers.Aggregates.Queries;
3334

@@ -47,6 +48,7 @@ public async Task<IReadOnlyCollection<ThingyMessage>> ExecuteQueryAsync(ThingyGe
4748
{
4849
var readModels = await _msSqlConnection.QueryAsync<MsSqlThingyMessageReadModel>(
4950
Label.Named("mssql-fetch-thingy-message-read-model"),
51+
ReadModelExtensions.GetConnectionStringName<MsSqlThingyMessageReadModel>(),
5052
cancellationToken,
5153
"SELECT * FROM [ReadModel-ThingyMessage] WHERE ThingyId = @ThingyId",
5254
new { ThingyId = query.ThingyId.Value })
@@ -56,4 +58,4 @@ public async Task<IReadOnlyCollection<ThingyMessage>> ExecuteQueryAsync(ThingyGe
5658
.ToList();
5759
}
5860
}
59-
}
61+
}

Source/EventFlow.MsSql.Tests/IntegrationTests/ReadStores/QueryHandlers/MsSqlThingyGetQueryHandler.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using EventFlow.Core;
2828
using EventFlow.MsSql.Tests.IntegrationTests.ReadStores.ReadModels;
2929
using EventFlow.Queries;
30+
using EventFlow.Sql.Extensions;
3031
using EventFlow.TestHelpers.Aggregates;
3132
using EventFlow.TestHelpers.Aggregates.Queries;
3233

@@ -46,11 +47,12 @@ public async Task<Thingy> ExecuteQueryAsync(ThingyGetQuery query, CancellationTo
4647
{
4748
var readModels = await _msSqlConnection.QueryAsync<MsSqlThingyReadModel>(
4849
Label.Named("mssql-fetch-test-read-model"),
50+
ReadModelExtensions.GetConnectionStringName<MsSqlThingyReadModel>(),
4951
cancellationToken,
5052
"SELECT * FROM [ReadModel-ThingyAggregate] WHERE AggregateId = @AggregateId",
5153
new { AggregateId = query.ThingyId.Value })
5254
.ConfigureAwait(false);
5355
return readModels.SingleOrDefault()?.ToThingy();
5456
}
5557
}
56-
}
58+
}

Source/EventFlow.MsSql.Tests/IntegrationTests/ReadStores/QueryHandlers/MsSqlThingyGetVersionQueryHandler.cs

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
using EventFlow.Core;
2828
using EventFlow.MsSql.Tests.IntegrationTests.ReadStores.ReadModels;
2929
using EventFlow.Queries;
30+
using EventFlow.Sql.Extensions;
3031
using EventFlow.TestHelpers.Aggregates.Queries;
3132

3233
namespace EventFlow.MsSql.Tests.IntegrationTests.ReadStores.QueryHandlers
@@ -45,6 +46,7 @@ public MsSqlThingyGetVersionQueryHandler(
4546
{
4647
var readModels = await _msSqlConnection.QueryAsync<MsSqlThingyReadModel>(
4748
Label.Named("mssql-fetch-test-read-model"),
49+
ReadModelExtensions.GetConnectionStringName<MsSqlThingyReadModel>(),
4850
cancellationToken,
4951
"SELECT * FROM [ReadModel-ThingyAggregate] WHERE AggregateId = @AggregateId",
5052
new { AggregateId = query.ThingyId.Value })

Source/EventFlow.MsSql.Tests/IntegrationTests/ReadStores/ReadModels/MsSqlThingyMessageReadModel.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
using System.Threading;
2727
using System.Threading.Tasks;
2828
using EventFlow.Aggregates;
29-
using EventFlow.MsSql.ReadStores.Attributes;
3029
using EventFlow.ReadStores;
30+
using EventFlow.Sql.ReadModels.Attributes;
3131
using EventFlow.TestHelpers.Aggregates;
3232
using EventFlow.TestHelpers.Aggregates.Entities;
3333
using EventFlow.TestHelpers.Aggregates.Events;
@@ -41,7 +41,7 @@ public class MsSqlThingyMessageReadModel : IReadModel,
4141
{
4242
public string ThingyId { get; set; }
4343

44-
[MsSqlReadModelIdentityColumn]
44+
[SqlReadModelIdentityColumn]
4545
public string MessageId { get; set; }
4646

4747
public string Message { get; set; }

0 commit comments

Comments
 (0)