diff --git a/documentation/documentation/events/appending.md b/documentation/documentation/events/appending.md index 4f54b8b924..382107efaa 100644 --- a/documentation/documentation/events/appending.md +++ b/documentation/documentation/events/appending.md @@ -40,8 +40,9 @@ Or have Marten use a Guid value that you provide yourself: <[sample:start-stream-with-existing-guid]> -**At this point, Marten forces you to use `System.Guid` as the id type of both events or streams** +For stream identity (strings vs. Guids), see <[linkto:documentation/events/identity]>. +Note that `StartStream` checks for existing stream and throws `ExistingStreamIdCollisionException` in case stream already exists. ## Appending Events @@ -55,4 +56,8 @@ If you have an existing stream, you can later append additional events with `IEv event stream if and only if the maximum event id for the stream matches the expected version after event insertions. Otherwise the transaction is aborted and a `EventStreamUnexpectedMaxEventIdException` exception is thrown. -<[sample:append-events-assert-on-eventid]> \ No newline at end of file +<[sample:append-events-assert-on-eventid]> + +### CreateStream vs. Append + +Both, `CreateStream` and `Append` can be used to start a new event stream. The difference with the methods is that `CreateStream` always checks for existing stream and throws `ExistingStreamIdCollisionException` in case stream already exists. \ No newline at end of file diff --git a/documentation/documentation/events/identity.md b/documentation/documentation/events/identity.md new file mode 100644 index 0000000000..63a112b6eb --- /dev/null +++ b/documentation/documentation/events/identity.md @@ -0,0 +1,13 @@ + + +The Event Store in Marten can identify and index streams either as GUIDs (`System.Guid`) or strings (`System.String`). This is reflected in the overloads of `IEventStore` such as `IEventStore.StartStream`, `IEventStore.Append` and `IEventStore.AggregateStream` that accept either `string` or `Guid` as the stream identifier. + +## Configuring Event Stream Identity + +Configuration of the stream identity is done through `StoreOptions.Events.StreamIdentity`. If not set, Marten defaults to `StreamIdentity.AsGuid`. The identity is configured once per store, whereby different stream identity types cannot be mixed. The following sample demonstrates configuring streams to be identified as strings. + +<[sample:eventstore-configure-stream-identity]> + +# Practical Implications + +Stream identity effects the underlying database schema of the Event Store related tables. Namely, using string identities configures `stream_id` in the `mt_events` table to be `varchar`, whereas `uuid` would be used for GUIDs. The same applies to the `id` column in `mt_streams` table. \ No newline at end of file diff --git a/documentation/documentation/events/index.md b/documentation/documentation/events/index.md index f1c66340af..ae412a075c 100644 --- a/documentation/documentation/events/index.md +++ b/documentation/documentation/events/index.md @@ -21,5 +21,4 @@ Now, let's say that we're starting a new "quest" with the first couple events, t <[sample:event-store-quickstart]> - - +In addition to generic `StartStream`, `IEventStore` has non-generic `StartStream` overload to create streams without associating them with aggregate type (stored in `mt_streams` table). \ No newline at end of file diff --git a/documentation/documentation/events/order.txt b/documentation/documentation/events/order.txt index 17b9c5ed73..d6f50905e5 100644 --- a/documentation/documentation/events/order.txt +++ b/documentation/documentation/events/order.txt @@ -1,4 +1,5 @@ schema +identity appending streams projections diff --git a/documentation/documentation/events/schema.md b/documentation/documentation/events/schema.md index e55b4888e6..d93238bd37 100644 --- a/documentation/documentation/events/schema.md +++ b/documentation/documentation/events/schema.md @@ -17,9 +17,11 @@ The events are stored in the `mt_events` table, with these columns: * `stream_id` - A foreign key to the event stream that contains the event * `version` - A numerical version of the event's position within its event stream * `data` - The actual event data stored as JSONB -* `type` - A string identifier for the event type taht's derived from the event type name. For example, events of type `IssueResolved` would be identified as "issue_resolved." The `type` +* `type` - A string identifier for the event type that's derived from the event type name. For example, events of type `IssueResolved` would be identified as "issue_resolved." The `type` column exists so that Marten can be effectively used without the underlying JSON serializer having to embed type metadata. * `timestamp` - A database timestamp written by the database when events are committed. +* `tenant_id` - Identifies the tenancy of the event +* `mt_dotnet_type` - The full name of the underlying event type, including assembly name, e.g. "Marten.Testing.Events.IssueResolved, Marten.Testing" The "Async Daemon" projection support keys off of the sequential id, but we retained the Guid id field for backward compatibility and to retain a potential way to uniquely identify events across databases. diff --git a/documentation/documentation/events/streams.md b/documentation/documentation/events/streams.md index e2a1ffab5c..2ce68cd131 100644 --- a/documentation/documentation/events/streams.md +++ b/documentation/documentation/events/streams.md @@ -14,11 +14,12 @@ The data returned is a list of `IEvent` objects, where each is a strong typed `E ## Stream State -If you just need to check on the state of an event stream - what version it is and what if any aggregate type it represents - you can use the +If you just need to check on the state of an event stream - what version (effectively the number of events in the stream) it is and what if any aggregate type it represents - you can use the `IEventStore.FetchStreamState()/FetchStreamStateAsync()` methods or through `IBatchQuery.Events.FetchStreamState()` shown below: <[sample:fetching_stream_state]> +Furthermore, `StreamState` contains metadata for when the stream was created, `StreamState.Created`, and when the stream was last updated, `StreamState.LastTimestamp`. ## Fetch a Single Event diff --git a/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs b/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs index 74570ea5b8..56980df0df 100644 --- a/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs +++ b/src/Marten.Testing/Events/event_store_with_string_identifiers_for_stream.cs @@ -10,12 +10,14 @@ namespace Marten.Testing.Events public class event_store_with_string_identifiers_for_stream : IntegratedFixture { public event_store_with_string_identifiers_for_stream() - { - StoreOptions(_ => + { + StoreOptions(storeOptions => { - _.Events.StreamIdentity = StreamIdentity.AsString; - _.Events.AsyncProjections.AggregateStreamsWith(); - }); + // SAMPLE: eventstore-configure-stream-identity + storeOptions.Events.StreamIdentity = StreamIdentity.AsString; + storeOptions.Events.AsyncProjections.AggregateStreamsWith(); + // ENDSAMPLE + }); } [Fact] diff --git a/src/Marten/Events/EventStore.cs b/src/Marten/Events/EventStore.cs index 58254292bc..7ea5cd4ee4 100644 --- a/src/Marten/Events/EventStore.cs +++ b/src/Marten/Events/EventStore.cs @@ -50,7 +50,7 @@ private void ensureAsStringStorage() private void ensureAsGuidStorage() { - if (StreamIdentity == StreamIdentity.AsString) throw new InvalidOperationException("This Marten event store is configured to identify streams with Guids"); + if (StreamIdentity == StreamIdentity.AsString) throw new InvalidOperationException("This Marten event store is configured to identify streams with strings"); _tenant.EnsureStorageExists(typeof(EventStream)); }