You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have been thinking of doing an implementation of this, but it would require the use of e.g. IAsyncEnumerable or something similar to keep the memory usage low. I have heard of users of EventFlow having literally thousands of events per aggregate and thus memory becomes a concern. It might be that EventFlow flow could ship with a "dumb" version that has a lot of caveats, e.g. does one at a time and doesn't care about changing aggregates after the process was done.
If you want to have an easy way to do it, merely get a list of all the aggregates from the store and use the IAggregateStore to iterate though all of them. You might want to partition the data and split it across multiple works.
Aggregates are intentionally only addressable by identity; the public API on IAggregateStore exposes LoadAsync, UpdateAsync, and StoreAsync per ID with no enumeration hook (Source/EventFlow/Aggregates/IAggregateStore.cs:34). Replaying all aggregates would require enumerating the entire event store, which the framework avoids because it is expensive and backend-specific.
Read-store abstractions mirror that philosophy: IReadModelStore<TReadModel> only guarantees GetAsync(id), UpdateAsync, and deletion methods (Source/EventFlow/ReadStores/IReadModelStore.cs:31, Source/EventFlow/ReadStores/ReadModelStore.cs:43). There is no cross-store GetAll because each persistence technology exposes different query semantics.
Available Options Today
In-memory read models already support bulk queries via IInMemoryReadStore<T>.FindAsync(Predicate<>), as used by the shipping sample to list all voyages (Source/EventFlow.Examples.Shipping.Queries.InMemory/Voyage/QueryHandlers/GetAllVoyagesQueryHandler.cs:33).
SQL-backed read models deliberately omit generic query helpers; instead you are expected to hit the read-model table using the connection of your choice (e.g., through Dapper or Entity Framework) inside an IQueryHandler. The documentation stresses wiring custom queries through the query processor rather than expecting canned GetAll helpers (Documentation/basics/queries.md:73).
Suggested Approach for Listing Users
Project UserAggregate events into a read model (UserReadModel) stored in the backend that fits your needs (SQL table, Mongo collection, etc.).
Implement an IQuery<UserListResult> plus handler that uses the store-specific API to fetch all documents: FindAsync(_ => true, …) for in-memory, a Mongo filter of {} for MongoDB, or a simple SELECT * FROM Users via ISqlConnection for SQL.
Register the query handler with EventFlow and call it through IQueryProcessor.ProcessAsync(new GetAllUsersQuery(), cancellationToken); so the rest of the application remains decoupled from persistence details.
Why No Built-In GetAll
A generic GetAll across aggregates or read stores would require EventFlow to understand paging, filtering, and backend-specific query plans—capabilities it deliberately omits to stay storage-agnostic and to keep replay costs explicit.
The framework expects consumer code to tailor read-side projections and queries to the UX needs; this is why only “read model by ID” and “in-memory predicate” queries ship out-of-the-box.
Next Steps
Decide which read-store implementation you use for users and expose an appropriate repository/query handler for bulk retrieval.
If the pattern is unclear to newcomers, consider a documentation PR referencing the shipping example to demonstrate the recommended approach for list views.
Activity
rasmus commentedon Mar 9, 2025
I have been thinking of doing an implementation of this, but it would require the use of e.g.
IAsyncEnumerableor something similar to keep the memory usage low. I have heard of users of EventFlow having literally thousands of events per aggregate and thus memory becomes a concern. It might be that EventFlow flow could ship with a "dumb" version that has a lot of caveats, e.g. does one at a time and doesn't care about changing aggregates after the process was done.If you want to have an easy way to do it, merely get a list of all the aggregates from the store and use the
IAggregateStoreto iterate though all of them. You might want to partition the data and split it across multiple works.rasmus commentedon Oct 26, 2025
.analyze
github-actions commentedon Oct 26, 2025
Issue Insight
IAggregateStoreexposesLoadAsync,UpdateAsync, andStoreAsyncper ID with no enumeration hook (Source/EventFlow/Aggregates/IAggregateStore.cs:34). Replaying all aggregates would require enumerating the entire event store, which the framework avoids because it is expensive and backend-specific.IReadModelStore<TReadModel>only guaranteesGetAsync(id),UpdateAsync, and deletion methods (Source/EventFlow/ReadStores/IReadModelStore.cs:31,Source/EventFlow/ReadStores/ReadModelStore.cs:43). There is no cross-storeGetAllbecause each persistence technology exposes different query semantics.Available Options Today
IInMemoryReadStore<T>.FindAsync(Predicate<>), as used by the shipping sample to list all voyages (Source/EventFlow.Examples.Shipping.Queries.InMemory/Voyage/QueryHandlers/GetAllVoyagesQueryHandler.cs:33).FindAsync/AsQueryable) for arbitrarily shaped queries (Source/EventFlow.MongoDB/ReadStores/MongoDbReadModelStore.cs:109).IQueryHandler. The documentation stresses wiring custom queries through the query processor rather than expecting cannedGetAllhelpers (Documentation/basics/queries.md:73).Suggested Approach for Listing Users
UserAggregateevents into a read model (UserReadModel) stored in the backend that fits your needs (SQL table, Mongo collection, etc.).IQuery<UserListResult>plus handler that uses the store-specific API to fetch all documents:FindAsync(_ => true, …)for in-memory, a Mongo filter of{}for MongoDB, or a simpleSELECT * FROM UsersviaISqlConnectionfor SQL.IQueryProcessor.ProcessAsync(new GetAllUsersQuery(), cancellationToken);so the rest of the application remains decoupled from persistence details.Why No Built-In
GetAllGetAllacross aggregates or read stores would require EventFlow to understand paging, filtering, and backend-specific query plans—capabilities it deliberately omits to stay storage-agnostic and to keep replay costs explicit.Next Steps
Your friendly neighborhood AI