Marten: EventStore AggregateStream never returns null

Created on 22 Jul 2020  路  2Comments  路  Source: JasperFx/marten

I'd expect that EventStore.AggregateStream(streamId) method would return null if there are no events (or not even a stream) for that stream identifier, but it actually creates a new stream instead (which all property values set to defaults) and saves both stream and aggregate in database (aggregate is defined as inline).

I've also seen null check on this thread, specifically:

public T Load<T>(string id, int? version = null) where T : AggregateBase
{
    using (var session = store.LightweightSession())
    {
        var aggregate = session.Events.AggregateStream<T>(id, version ?? 0);
        return aggregate ?? throw new InvalidOperationException($"No aggregate by id {id}.");
    }
}

but as far as I could test, this method will never throw InvalidOperationException.

I'm just interested whether this is expected behaviour and how should I use this API correctly. From what I've tested so far, I can load the document via documentSession.Load<MyDocument>(streamId); (this returns null if it doesn't exist), but I'm not sure if I can use this normally (meaning append new events internally on this object, as if it was fetched via AggregateStreamAsync, or AggregateStreamAsync is somehow different from Load - in regards to fetching latest aggregate that's stored in database and using it later on).

Thank you.

event store question

All 2 comments

@huberzeljko I'm aware of that issue. In my opinion, it's a bug. We won't be able to fix that in v3, as it'd be kinda big breaking change, however, if others agree I can change that behaviour to be consistent in v4 (in my opinion it should return null). @jeremydmiller do you happen to remember why is it like that?

Regarding AggregateStream vs Load. Load is getting the snapshot directly from a document that represents the latest version of the stream. AggregateStream works as follows:

  • get all events for the selected stream id (ordered by the occurrence - stream version),
  • create aggregate based on default constructor or creates an uninitialized object,
  • for each event, call Apply method for Aggregate.

Unfortunately, it does not check if there were events at all.

If you'd like to get null then you'd need to perform additional query - session.Events.FetchStreamState it should return null if stream was not found. See more in https://martendb.io/documentation/events/streams/

This has been fixed in the V4 "projections" branch.

Was this page helpful?
0 / 5 - 0 ratings