ITLab.Template.DevPack.Data
Defines repository and unit-of-work contracts, paginated and grouped query primitives, and utility discriminated types.
Componentes
| Tipo | Nome | Responsabilidade |
|---|---|---|
| Interface | IRepository<T> | Repository contract with CRUD operations and unit-of-work access |
| Interface | IUnitOfWork | Commit boundary for persistence operations |
| Enum | EOrderDirection | Sort direction for ordered queries: asc, desc |
| Abstract Class | PaginatedQueryBase | Base class for paginated query requests (page, size, order, group, filter) |
| Abstract Class | PaginatedQueryBase<TDto> | Typed variant implementing IQuery<PaginatedList<TDto>> |
| Class | PaginatedList<T> | Paginated slice of query results with metadata (page, totalCount, hasPrev/Next) |
| Class | GroupableList<T> | Paginated list with server-side grouping support |
| Class | Group<T> | Represents a grouped set of items with a composite key and item count |
| Class | GroupKey | Immutable composite key identifying a group (dictionary of field→value pairs) |
| Struct | OneOf<T0, T1> | Lightweight discriminated union for dual-result scenarios |
| Class | OneOfEnumerable<T> | OneOf alias carrying an IEnumerable<T> in one arm |
| Class | OneOfList<T> | OneOf alias carrying an IList<T> in one arm |
| Static Class | OneOf | Factory helpers for creating OneOf instances |
| Static Class | QueryFilter | DSL parser that converts a filter string into an Expression<Func<T, bool>> compatible with EF Core and in-memory queries (DSL version 1.0.2) |
Como usar
// Paginated query — products inherit PaginatedQueryBase<TDto>.
// PaginatedQueryBase<T> is an abstract CLASS — records cannot inherit from
// non-record base types in C# (CS8865/CS0115). Declare paginated queries
// as `class`, not `record`.
public sealed class ListOrdersQuery : PaginatedQueryBase<OrderDto>
{
}
// Repository usage in an application handler.
public async Task<Result> Handle(CreateCustomerCommand command)
{
_repository.Add(new Customer(command.Name));
await _repository.Commit();
return Result.Success();
}
// OneOf for a handler that returns either a list or a grouped list.
OneOf<PaginatedList<OrderDto>, GroupableList<OrderDto>> result = await mediator.Send(query);
result.Match(list => list.Items, grouped => grouped.Groups.SelectMany(g => g.Items));
// QueryFilter: parse a filter string from the request into a LINQ predicate.
var predicate = QueryFilter.ParseFilter<Order>("status eq 'Active' and total gt 100");
var orders = await dbContext.Orders.Where(predicate).ToListAsync();
The paginated-query declaration above — auto-suficiente, verificado pelo smoke check (regression do record : PaginatedQueryBase<T>):
public sealed record OrderDto(Guid Id, string Customer);
public sealed class ListOrdersQuery : PaginatedQueryBase<OrderDto>
{
}
O que não fazer
- Do not expose ORM-specific APIs through
IRepository<T>consumers. - Do not skip
IUnitOfWorkcommit boundaries in write flows. - Do not add product-specific query properties to
PaginatedQueryBase— derive from it instead. - Do not declare
record : PaginatedQueryBase<T>— base é classe abstrata e records não herdam de classes não-record. Useclass : PaginatedQueryBase<T>.
Extensão pelo produto
- Products implement repositories with EF Core or other stores while preserving
IRepository<T>semantics. - Products derive from
PaginatedQueryBase<TDto>and add product-specific filter properties. - Products may adopt
OneOfEnumerable/OneOfListaliases for flexible read-model payloads. - Para registrar endpoints sobre
PaginatedQueryBase<TDto>, verMapPaginatedGetemareas/Extensions/README.md(DevPack 10.3.0+) — encapsula o bind individual depageNumber/pageSize/orderBy/order/filter/paginated.