Expected version not working how I thought it would...

So, a couple things:

  • The inline docs say that ExpectedVersion.EmptyStream should equal 0 but it’s actually -1 which is the same as ExpectedVersion.NoStream

Not sure if that’s on purpose or if it’s a bug.

AppendToStreamAsync can take one or more EventDatas but asks for a single expected version. My case right now attempts to save a few events for a new entity so it’s a new stream of Survey-. What I did was set the expected version like this:

var expectedVersion = first.Version == 0
? ExpectedVersion.NoStream
: first.Version;

``

My reasoning is that if it’s event 0, then it’s a new stream, thus should not exist. I’m also assuming that it’s checking this version against the first EventData in the stream I’m saving. I’m getting WrongExpectedVersionException, but when I look at the event store browser, the stream was created and has a single event.

I feel like I need some clarification on how this is supposed to work.

NoStream vs 0 are slightly different. Try setting metadata first and
they will have differing behaviour.

EG
0 no metadata = both work
0 with metadata 0 works not nostream
stream exists = both fail

Not quite sure what you mean by setting the metadata “first”. All of my events have the metadata set in a base class, then when I convert that object to an EventData object, I just pass the metadata in as an argument.

private async Task AppendEventsAsync(string streamName, params EventInfo[] infos)
{
if (string.IsNullOrEmpty(streamName))
throw new ArgumentNullException(nameof(streamName));
if (infos == null || !infos.Any())
throw new ArgumentNullException(nameof(infos));
var first = infos[0];
if (infos.Any(i => i.EntityId != first.EntityId))
throw new InvalidOperationException(“All events in this transaction must belong to the same entity.”);
var stream = infos
.Select(info => new EventData(
info.EventId,
info.EventType,
true,
info.GetData(),
info.Metadata.GetData()))
.ToArray();
var expectedVersion = first.Version == 0
? ExpectedVersion.NoStream
: first.Version;
try
{
await _connection
.AppendToStreamAsync(streamName, expectedVersion, stream)
.ConfigureAwait(false);
}
catch (WrongExpectedVersionException ex)
{
var dirtyStreamEx = new DirtyStreamException(
$"Expected version {expectedVersion}, but the current version was different. " +
"This happens when the stream was modified by some other process before this " +
“process was able to complete (concurrency)”, ex);
throw dirtyStreamEx;
}
}

``

stream metadata such as $maxAge/$maxCount etc

So if I’m understanding you right, then if I never set the stream metadata, then either 0 or NoStream should work? I’m not setting the stream metadata but NoStream is not working, so I’m still confused.

There is a special use case here involving NoStream. You can "created"
a stream by setting an ACL etc which requires a distinction between
this case and 0. EG I can specify "only do this write providing the
stream does not exist". A stream with metadata set is an empty stream
(no items) not a non-existing stream. A vocbulary different would
likely help

Ok so I removed that line completely and let it just pass in the actual version (0) and it’s still giving the same error. The stream metadata is still empty. I also tried NoStream and got the same error. It’s also still writing to the stream despite the exception.

Correction, I used EmptyStream, not NoStream

I think what’s really going on here is that I don’t know the difference between an event version and a stream version. I thought the check was supposed to make sure the new events being written are equal to the last event version + 1. But now I’m thinking this has nothing to do with the event and everything to do with the stream and I don’t quite understand when or why the stream version would change particularly when mine doesn’t even have any metadata

I tend to think of it as ‘whats the version of the last event written?’ So current min - 1.

That appears to not be true though. The last event written was 0, but the stream’s metadata doesn’t even have an entry in it and it still throws errors when I send expected version = 0

if there is an event expected version should be 1 (that is the version
the event will be)

So if my aggregate is retrieved/replayed and the last event is 6 and I add two more events (what would be 7 and 8), when I go to write to the stream, then expected version is 7?

yes as that is the expected version.

Ok I’ll try that. I probably sound dense, but for whatever reason I thought expected version meant “I expect that last version you have is x” vs. “The next version number would be x”

When I get back to it to try it out, I’ll report back to confirm we’re back on the same page :slight_smile:

That has been my understanding as well. But maybe I’ve done the same off by one error on all implementations.