Skip to content

Command & Query Abstractions

Casey edited this page Apr 6, 2025 · 3 revisions

EntityAxis provides a set of generic interfaces and base types to help you implement the Command Query Responsibility Segregation (CQRS) pattern cleanly and consistently.

These abstractions decouple your application logic from infrastructure, enabling automated registration, handler generation, and testability out of the box.


✍️ Commands

Command interfaces define write operations that change state. These are typically implemented in your infrastructure layer.

Core Interfaces

public interface ICreate<TEntity, TKey>
{
    Task<TKey> CreateAsync(TEntity entity, CancellationToken cancellationToken = default);
}

public interface IUpdate<TEntity, TKey>
{
    Task<TKey> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
}

public interface IDelete<TEntity, TKey>
{
    Task DeleteAsync(TKey id, CancellationToken cancellationToken = default);
}

Composite Command Service

For convenience, you can implement ICommandService<TEntity, TKey> to bundle all three:

public interface ICommandService<TEntity, TKey> :
    ICreate<TEntity, TKey>,
    IUpdate<TEntity, TKey>,
    IDelete<TEntity, TKey>
{ }

🔍 Queries

Query interfaces define read operations that do not mutate state. These also live in the infrastructure layer and are typically implemented using EF Core or another persistence provider.

Core Interfaces

public interface IGetById<TEntity, TKey>
{
    Task<TEntity?> GetByIdAsync(TKey id, CancellationToken cancellationToken = default);
}

public interface IGetAll<TEntity, TKey>
{
    Task<List<TEntity>> GetAllAsync(CancellationToken cancellationToken = default);
}

public interface IGetPaged<TEntity, TKey>
{
    Task<PagedResult<TEntity>> GetPagedAsync(int page, int pageSize, CancellationToken cancellationToken = default);
}

Composite Query Service

Use IQueryService<TEntity, TKey> to implement all three query interfaces in one:

public interface IQueryService<TEntity, TKey> :
    IGetById<TEntity, TKey>,
    IGetAll<TEntity, TKey>,
    IGetPaged<TEntity, TKey>
{ }

🤝 Benefits of Using Abstractions

  • ✅ Consistent structure across all entities
  • 🔄 Easy automatic handler + validator registration
  • 🔧 Simplifies mocking and testing
  • 🔍 Supports vertical slice architecture
  • 🔗 Enables integration with EF Core and MediatR seamlessly

📚 See Also

Clone this wiki locally