In general you should not query the saga store. The schema isn’t optimized for it.
Your pattern to publish an event to indicate a certain state is very common. A subscriber can decide to store that for its UI to show. In your case very specific to your query requirement “orders that have not yet shipped”. Another component could in isolation become fully responsible in tracking and communication/visualizing this.
Another common pattern is to have a Handler on the same message that stores data in a view model.
For example:
class MySaga : Saga<MyState>, IHandleMessages<MyMessage>
{
public async Task Handle(MyMessage message, IMessageHandlerContext context)
{
// Only store 2 properties required for this policy
}
}
class MyHandlerThatUpdatesAViewModel, IHandleMessages<MyMessage>
{
public async Task Handle(MyMessage message, IMessageHandlerContext context)
{
// Store all data for viewing purposes
}
}
That separates the concerns as well. You could even have multiple different view models that store different things or for different reasons (for example, full-text search).
Your second query “Get order” is a very different query similarly as querying for an order its shipping status.
Keep in mind that often sagas are only orchestrators that make decisions based on a subset of data from their stored and incoming state.
You could have another component that blindly adds everything into a single viewmodel that stores everything in a single table (like the secondary handler example) wilth lots of nullable columns and be eventually consistent with the processes that each have ownership on their snippets of data required for their.
Last is very common often state can be assumed based on the fact that certain data doesn’t exist yet. For example, order isn’t known to be shipped because shipping info regarding the parcel could not be queried. Very often this is only a user-interface concern. If this is important for some business process often you want to track that based on business event that is defined in the process.