Skip to content

Commit 7f42c6d

Browse files
committed
Merge branch 'develop'
2 parents ceb6977 + be44e5e commit 7f42c6d

34 files changed

+491
-250
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.png filter=lfs diff=lfs merge=lfs -text
+3
Loading

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ several areas that you could help out with.
156156
point to specfic EventFlow functionality that might be done better, then
157157
please create an issue or ask in the Gitter chat
158158

159+
## Thanks
160+
161+
![ReSharper](./Documentation/Images/logo_resharper.png)
162+
163+
159164
## License
160165

161166
```

RELEASE_NOTES.md

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
1-
### New in 0.17 (not released yet)
1+
### New in 0.18 (not released yet)
2+
3+
* POTENTIAL DATA LOSS for the **files event store**: The EventFlow
4+
internal functionality regarding event stores has been refactored resulting
5+
in information regarding aggregate names being removed from the event
6+
persistence layer. The files based event store no longer stores its events in
7+
the path `[STORE PATH]\[AGGREGATE NAME]\[AGGREGATE ID]\[SEQUENCE].json`, but
8+
in the path `[STORE PATH]\[AGGREGATE ID]\[SEQUENCE].json`. Thus if you are
9+
using the files event store for tests, you should move the events into the
10+
new file structure. Alternatively, implement the new `IFilesEventLocator` and
11+
provide your own custom event file layout.
12+
* Breaking: Event stores have been split into two parts, the `IEventStore`
13+
and the new `IEventPersistence`. `IEventStore` has the same interface before
14+
but the implementation is now no longer responsible for persisting the events,
15+
only converting and serializing the persisted events. `IEventPersistence`
16+
handles the actual storing of events and thus if any custom event stores have
17+
been implemented, they should implement to the new `IEventPersistence`
18+
instead.
19+
* New: Added `IEntity`, `IEntity<>` and an optional `Entity<>` that developers
20+
can use to implement DDD entities.
21+
22+
### New in 0.17.1134 (released 2015-09-28)
223

324
* Fixed: Using NuGet package `EventFlow.Autofac` causes an exception with the
425
message `The type 'EventFlow.Configuration.Registrations.AutofacStartable'

Source/EventFlow.EventStores.EventStore.Tests/IntegrationTests/EventStoreEventStoreTestConfiguration.cs

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
using System.Net;
2424
using System.Threading;
2525
using System.Threading.Tasks;
26-
using EventFlow.Aggregates;
2726
using EventFlow.Configuration;
2827
using EventFlow.Core;
2928
using EventFlow.EventStores.EventStore.Extensions;

Source/EventFlow.EventStores.EventStore/EventFlow.EventStores.EventStore.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<Compile Include="..\SolutionInfo.cs">
5252
<Link>Properties\SolutionInfo.cs</Link>
5353
</Compile>
54-
<Compile Include="EventStoreEventStore.cs" />
54+
<Compile Include="EventStoreEventPersistence.cs" />
5555
<Compile Include="Extensions\EventFlowOptionsExtensions.cs" />
5656
<Compile Include="Properties\AssemblyInfo.cs" />
5757
</ItemGroup>

Source/EventFlow.EventStores.EventStore/EventStoreEventStore.cs renamed to Source/EventFlow.EventStores.EventStore/EventStoreEventPersistence.cs

+17-25
Original file line numberDiff line numberDiff line change
@@ -27,39 +27,36 @@
2727
using System.Threading;
2828
using System.Threading.Tasks;
2929
using EventFlow.Aggregates;
30+
using EventFlow.Core;
3031
using EventFlow.Exceptions;
3132
using EventFlow.Logs;
3233
using EventStore.ClientAPI;
3334
using EventStore.ClientAPI.Exceptions;
3435

3536
namespace EventFlow.EventStores.EventStore
3637
{
37-
public class EventStoreEventStore : EventStoreBase
38+
public class EventStoreEventPersistence : IEventPersistence
3839
{
40+
private readonly ILog _log;
3941
private readonly IEventStoreConnection _connection;
4042

4143
private class EventStoreEvent : ICommittedDomainEvent
4244
{
4345
public string AggregateId { get; set; }
44-
public string AggregateName { get; set; }
4546
public string Data { get; set; }
4647
public string Metadata { get; set; }
4748
public int AggregateSequenceNumber { get; set; }
4849
}
4950

50-
public EventStoreEventStore(
51+
public EventStoreEventPersistence(
5152
ILog log,
52-
IAggregateFactory aggregateFactory,
53-
IEventJsonSerializer eventJsonSerializer,
54-
IEventUpgradeManager eventUpgradeManager,
55-
IEventStoreConnection connection,
56-
IEnumerable<IMetadataProvider> metadataProviders)
57-
: base(log, aggregateFactory, eventJsonSerializer, eventUpgradeManager, metadataProviders)
53+
IEventStoreConnection connection)
5854
{
55+
_log = log;
5956
_connection = connection;
6057
}
6158

62-
protected override async Task<AllCommittedEventsPage> LoadAllCommittedDomainEvents(
59+
public async Task<AllCommittedEventsPage> LoadAllCommittedEvents(
6360
GlobalPosition globalPosition,
6461
int pageSize,
6562
CancellationToken cancellationToken)
@@ -104,19 +101,17 @@ private static Position ParsePosition(GlobalPosition globalPosition)
104101
return new Position(commitPosition, preparePosition);
105102
}
106103

107-
protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync<TAggregate, TIdentity>(
108-
TIdentity id,
104+
public async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync(
105+
IIdentity id,
109106
IReadOnlyCollection<SerializedEvent> serializedEvents,
110107
CancellationToken cancellationToken)
111108
{
112-
var aggregateName = typeof (TAggregate).Name;
113109
var committedDomainEvents = serializedEvents
114110
.Select(e => new EventStoreEvent
115111
{
116112
AggregateSequenceNumber = e.AggregateSequenceNumber,
117113
Metadata = e.SerializedMetadata,
118114
AggregateId = id.Value,
119-
AggregateName = aggregateName,
120115
Data = e.SerializedData
121116
})
122117
.ToList();
@@ -126,7 +121,7 @@ protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> Commit
126121
.Select(e =>
127122
{
128123
var guid = Guid.Parse(e.Metadata["guid"]);
129-
var eventType = string.Format("{0}.{1}.{2}", aggregateName, e.Metadata.EventName, e.Metadata.EventVersion);
124+
var eventType = string.Format("{0}.{1}.{2}", e.Metadata[MetadataKeys.AggregateName], e.Metadata.EventName, e.Metadata.EventVersion);
130125
var data = Encoding.UTF8.GetBytes(e.SerializedData);
131126
var meta = Encoding.UTF8.GetBytes(e.SerializedMetadata);
132127
return new EventData(guid, eventType, true, data, meta);
@@ -142,9 +137,9 @@ protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> Commit
142137
{
143138
await transaction.WriteAsync(eventDatas).ConfigureAwait(false);
144139
var writeResult = await transaction.CommitAsync().ConfigureAwait(false);
145-
Log.Verbose(
146-
"Wrote aggregate {0} with version {1} ({2},{3})",
147-
aggregateName,
140+
_log.Verbose(
141+
"Wrote entity {0} with version {1} ({2},{3})",
142+
id,
148143
writeResult.NextExpectedVersion - 1,
149144
writeResult.LogPosition.CommitPosition,
150145
writeResult.LogPosition.PreparePosition);
@@ -158,8 +153,8 @@ protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> Commit
158153
return committedDomainEvents;
159154
}
160155

161-
protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCommittedEventsAsync<TAggregate, TIdentity>(
162-
TIdentity id,
156+
public async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCommittedEventsAsync(
157+
IIdentity id,
163158
CancellationToken cancellationToken)
164159
{
165160
var streamEvents = new List<ResolvedEvent>();
@@ -182,9 +177,7 @@ protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCo
182177
return Map(streamEvents);
183178
}
184179

185-
public override Task DeleteAggregateAsync<TAggregate, TIdentity>(
186-
TIdentity id,
187-
CancellationToken cancellationToken)
180+
public Task DeleteEventsAsync(IIdentity id, CancellationToken cancellationToken)
188181
{
189182
return _connection.DeleteStreamAsync(id.Value, ExpectedVersion.Any);
190183
}
@@ -197,10 +190,9 @@ private static IReadOnlyCollection<EventStoreEvent> Map(IEnumerable<ResolvedEven
197190
AggregateSequenceNumber = e.Event.EventNumber + 1,
198191
Metadata = Encoding.UTF8.GetString(e.Event.Metadata),
199192
AggregateId = e.OriginalStreamId,
200-
AggregateName = e.Event.EventType.Split('.')[0],
201193
Data = Encoding.UTF8.GetString(e.Event.Data),
202194
})
203195
.ToList();
204196
}
205197
}
206-
}
198+
}

Source/EventFlow.EventStores.EventStore/Extensions/EventFlowOptionsExtensions.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222

2323
using System.Net;
2424
using EventFlow.Configuration;
25-
using EventFlow.Configuration.Registrations;
2625
using EventFlow.Core;
2726
using EventFlow.Extensions;
2827
using EventStore.ClientAPI;
@@ -34,7 +33,7 @@ public static class EventFlowOptionsExtensions
3433
public static IEventFlowOptions UseEventStoreEventStore(
3534
this IEventFlowOptions eventFlowOptions)
3635
{
37-
return eventFlowOptions.UseEventStore<EventStoreEventStore>();
36+
return eventFlowOptions.UseEventStore<EventStoreEventPersistence>();
3837
}
3938

4039
public static IEventFlowOptions UseEventStoreEventStore(
@@ -59,7 +58,7 @@ public static IEventFlowOptions UseEventStoreEventStore(
5958

6059
return eventFlowOptions
6160
.RegisterServices(f => f.Register(r => eventStoreConnection, Lifetime.Singleton))
62-
.UseEventStore<EventStoreEventStore>();
61+
.UseEventStore<EventStoreEventPersistence>();
6362
}
6463
}
6564
}

Source/EventFlow.EventStores.MsSql/EventFlow.EventStores.MsSql.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
</Compile>
5151
<Compile Include="EventFlowEventStoresMsSql.cs" />
5252
<Compile Include="Extensions\EventFlowOptionsExtensions.cs" />
53-
<Compile Include="MsSqlEventStore.cs" />
53+
<Compile Include="MsSqlEventPersistence.cs" />
5454
<Compile Include="Properties\AssemblyInfo.cs" />
5555
</ItemGroup>
5656
<ItemGroup>

Source/EventFlow.EventStores.MsSql/Extensions/EventFlowOptionsExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static class EventFlowOptionsExtensions
2828
{
2929
public static IEventFlowOptions UseMssqlEventStore(this IEventFlowOptions eventFlowOptions)
3030
{
31-
return eventFlowOptions.UseEventStore<MsSqlEventStore>();
31+
return eventFlowOptions.UseEventStore<MsSqlEventPersistence>();
3232
}
3333
}
3434
}

Source/EventFlow.EventStores.MsSql/MssqlEventStore.cs renamed to Source/EventFlow.EventStores.MsSql/MsSqlEventPersistence.cs

+15-29
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
namespace EventFlow.EventStores.MsSql
3636
{
37-
public class MsSqlEventStore : EventStoreBase
37+
public class MsSqlEventPersistence : IEventPersistence
3838
{
3939
public class EventDataModel : ICommittedDomainEvent
4040
{
@@ -47,21 +47,18 @@ public class EventDataModel : ICommittedDomainEvent
4747
public int AggregateSequenceNumber { get; set; }
4848
}
4949

50+
private readonly ILog _log;
5051
private readonly IMsSqlConnection _connection;
5152

52-
public MsSqlEventStore(
53+
public MsSqlEventPersistence(
5354
ILog log,
54-
IAggregateFactory aggregateFactory,
55-
IEventJsonSerializer eventJsonSerializer,
56-
IEventUpgradeManager eventUpgradeManager,
57-
IEnumerable<IMetadataProvider> metadataProviders,
5855
IMsSqlConnection connection)
59-
: base(log, aggregateFactory, eventJsonSerializer, eventUpgradeManager, metadataProviders)
6056
{
57+
_log = log;
6158
_connection = connection;
6259
}
6360

64-
protected override async Task<AllCommittedEventsPage> LoadAllCommittedDomainEvents(
61+
public async Task<AllCommittedEventsPage> LoadAllCommittedEvents(
6562
GlobalPosition globalPosition,
6663
int pageSize,
6764
CancellationToken cancellationToken)
@@ -97,17 +94,13 @@ ORDER BY
9794
return new AllCommittedEventsPage(new GlobalPosition(nextPosition.ToString()), eventDataModels);
9895
}
9996

100-
protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync<TAggregate, TIdentity>(
101-
TIdentity id,
102-
IReadOnlyCollection<SerializedEvent> serializedEvents,
103-
CancellationToken cancellationToken)
97+
public async Task<IReadOnlyCollection<ICommittedDomainEvent>> CommitEventsAsync(IIdentity id, IReadOnlyCollection<SerializedEvent> serializedEvents, CancellationToken cancellationToken)
10498
{
10599
if (!serializedEvents.Any())
106100
{
107101
return new ICommittedDomainEvent[] {};
108102
}
109103

110-
var aggregateType = typeof(TAggregate);
111104
var eventDataModels = serializedEvents
112105
.Select((e, i) => new EventDataModel
113106
{
@@ -120,10 +113,9 @@ protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> Commit
120113
})
121114
.ToList();
122115

123-
Log.Verbose(
124-
"Committing {0} events to MSSQL event store for aggregate {1} with ID '{2}'",
116+
_log.Verbose(
117+
"Committing {0} events to MSSQL event store for entity with ID '{1}'",
125118
eventDataModels.Count,
126-
aggregateType.Name,
127119
id);
128120

129121
const string sql = @"
@@ -151,9 +143,8 @@ OUTPUT CAST(INSERTED.GlobalSequenceNumber as bigint)
151143
{
152144
if (exception.Number == 2601)
153145
{
154-
Log.Verbose(
155-
"MSSQL event insert detected an optimistic concurrency exception for aggregate '{0}' with ID '{1}'",
156-
aggregateType.Name,
146+
_log.Verbose(
147+
"MSSQL event insert detected an optimistic concurrency exception for entity with ID '{0}'",
157148
id);
158149
throw new OptimisticConcurrencyException(exception.Message, exception);
159150
}
@@ -174,9 +165,7 @@ OUTPUT CAST(INSERTED.GlobalSequenceNumber as bigint)
174165
return eventDataModels;
175166
}
176167

177-
protected override async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCommittedEventsAsync<TAggregate, TIdentity>(
178-
TIdentity id,
179-
CancellationToken cancellationToken)
168+
public async Task<IReadOnlyCollection<ICommittedDomainEvent>> LoadCommittedEventsAsync(IIdentity id, CancellationToken cancellationToken)
180169
{
181170
const string sql = @"
182171
SELECT
@@ -198,9 +187,7 @@ ORDER BY
198187
return eventDataModels;
199188
}
200189

201-
public override async Task DeleteAggregateAsync<TAggregate, TIdentity>(
202-
TIdentity id,
203-
CancellationToken cancellationToken)
190+
public async Task DeleteEventsAsync(IIdentity id, CancellationToken cancellationToken)
204191
{
205192
const string sql = @"DELETE FROM EventFlow WHERE AggregateId = @AggregateId";
206193
var affectedRows = await _connection.ExecuteAsync(
@@ -210,11 +197,10 @@ public override async Task DeleteAggregateAsync<TAggregate, TIdentity>(
210197
new {AggregateId = id.Value})
211198
.ConfigureAwait(false);
212199

213-
Log.Verbose(
214-
"Deleted aggregate '{0}' with ID '{1}' by deleting all of its {2} events",
215-
typeof(TAggregate).Name,
200+
_log.Verbose(
201+
"Deleted entity with ID '{0}' by deleting all of its {1} events",
216202
id,
217203
affectedRows);
218204
}
219205
}
220-
}
206+
}

Source/EventFlow.MsSql.Tests/IntegrationTests/MsSqlIntegrationTestConfiguration.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public override IRootResolver CreateRootResolver(IEventFlowOptions eventFlowOpti
5151

5252
var resolver = eventFlowOptions
5353
.ConfigureMsSql(MsSqlConfiguration.New.SetConnectionString(TestDatabase.ConnectionString.Value))
54-
.UseEventStore<MsSqlEventStore>()
54+
.UseEventStore<MsSqlEventPersistence>()
5555
.UseMssqlReadModel<MsSqlTestAggregateReadModel>()
5656
.CreateResolver();
5757

Source/EventFlow.Tests/IntegrationTests/ConfigurationTests.cs

+4-6
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2121
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222

23-
using System;
2423
using EventFlow.EventStores;
2524
using EventFlow.EventStores.InMemory;
26-
using EventFlow.Extensions;
2725
using FluentAssertions;
2826
using NUnit.Framework;
2927

@@ -40,12 +38,12 @@ public void CanResolve()
4038
.CreateResolver(true);
4139

4240
// Act
43-
IEventStore eventStore = null;
44-
Assert.DoesNotThrow(() => eventStore = resolver.Resolve<IEventStore>());
41+
IEventPersistence eventPersistence = null;
42+
Assert.DoesNotThrow(() => eventPersistence = resolver.Resolve<IEventPersistence>());
4543

4644
// Assert
47-
eventStore.Should().NotBeNull();
48-
eventStore.Should().BeAssignableTo<InMemoryEventStore>();
45+
eventPersistence.Should().NotBeNull();
46+
eventPersistence.Should().BeAssignableTo<InMemoryEventPersistence>();
4947
}
5048
}
5149
}

Source/EventFlow.Tests/UnitTests/EventStores/EventStoreTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
namespace EventFlow.Tests.UnitTests.EventStores
3636
{
37-
public class EventStoreTests : TestsFor<InMemoryEventStore>
37+
public class EventStoreTests : TestsFor<InMemoryEventPersistence>
3838
{
3939
private Mock<IEventUpgradeManager> _eventUpgradeManagerMock;
4040
private Mock<IEventJsonSerializer> _eventJsonSerializerMock;

0 commit comments

Comments
 (0)