"Create or modify a CoreEx Infrastructure-layer repository. USE FOR: new repository class, adding CRUD operations, adding a custom query (QueryArgsConfig<TSelf>), bidirectional mapper (BiDirectionMapper), EfDb/CosmosDb model accessor, Result<T> pipeline variants. DO NOT USE FOR: Application-layer service logic, domain invariants, typed HTTP clients/adapters (those follow adapter conventions in the infrastructure instructions, not this skill)."
Resources
1Install
npx skillscat add avanade/coreex/coreex-repository Install via the SkillsCat registry.
CoreEx: Repository
Guides you through creating or modifying a CoreEx Infrastructure-layer repository in Infrastructure/Repositories/. Covers CRUD delegates, custom queries, bidirectional mappers, EfDb or CosmosDb accessors, and Result<T> pipelines.
When to Use
- New repository class for an entity (scaffold, EfDb/CosmosDb accessor, mapper, registration)
- Adding a CRUD operation (get/create/update/delete) using EfDb delegate shortcuts
- Adding a custom query method with
QueryArgsConfigdynamic filtering/ordering - Adding a
BiDirectionMapper(Contract ↔ Persistence) inInfrastructure/Mapping/ - Adding or modifying an
EfDbMappedModel/EfDbModelaccessor on*EfDb, or aCosmosDbContainer<TModel>/CosmosDbMappedContainer<...>accessor on*CosmosDb - Switching a method to the
Result<T>/*WithResultAsyncpipeline
When Not to Use
- Application-layer service logic — inject the repository interface, do not modify it from Infrastructure
- Domain aggregates, entities, value objects — those belong in the Domain layer
- Persistence model class creation — those are generated by the
*.Databasetooling; rundotnet run -- CodeGenthere
Quick Reference
Clarifying questions before writing any code:
0. Resolve from state first. Read the solution-root AGENTS.md Feature Configuration for data-provider (SqlServer / Postgres / Cosmos — gates this skill) and check whether a *.Domain project exists (Domain-mapping vs contract-mapping). Only ask for what is unresolved; re-state resolved values for confirmation.
- Which entity? Which database type (
PostgreSQL/SQL Server/Cosmos)? Check the project'sProgram.cs. - New repository or adding to an existing one?
- Operations needed: Get / Create / Update / Delete / Query?
- Does the project use
Result<T>/ ROP pipelines? (→*WithResultAsync— per-project style choice, not tied to DDD) - Does the query need dynamic filtering/ordering? (→
QueryArgsConfig<TSelf>) — if yes, collect the complete field list from the developer before writing any code: for each filter field the name, property type, allowed operators, and model/LINQ name if it differs from the contract name; for each order-by field the name and whether it should be in the default sort or always appended. AI cannot infer these from the entity shape.
Key rules at a glance:
[ScopedService<IInterface>]on every repository class — auto-registers in DI- Primary constructor: relational example
public class ProductRepository(ProductsEfDb ef) : IProductRepository; Cosmos examplepublic class CustomerRepository(CustomersCosmosDb cosmos) : ICustomerRepository; always guard the injected accessor withThrowIfNull() - Use the provider's typed accessors:
EfDbdelegate shortcuts (GetAsync,CreateAsync,UpdateAsync,DeleteAsync) for relational domains;CosmosDbMappedContainer/CosmosDbContainerdelegates for Cosmos domains. Never write rawDbContextCRUD or instantiate aCosmosClientin the repository. DataResult<T>return for Create/Update;DataResultfor Delete — includes mutation flag for event decisions*WithResultAsyncvariants forResult<T>ROP pipelines (per-project style choice)BiDirectionMapper: override bothOnMapoverloads; mapIdexplicitly; never mapETagorChangeLog— base mapper owns themQueryArgsConfig<TSelf>: create a dedicated{Name}QueryArgsConfig : QueryArgsConfig<{Name}QueryArgsConfig>class per entity inInfrastructure/Repositories/; access via.Default; call.Parse(query).ThrowOnError()before use — never instantiate per-request. Relational queries materialize fromIQueryable<TModel>extensions; Cosmos queries materialize fromCosmosDbQuery<TModel>instance methods (Container.Query(...).ToMappedItemsResultAsync(...)).AddReferenceDataField<TRef>(field, model, ...):fieldis always the contract's generated nav property ({Name}, never{Name}Code) — a fixed, documented source-generator convention, not something to verify by exploring generated codeToMappedItemsResultAsync(mapper, paging, cancellationToken: cancellationToken): always passcancellationTokenby name —autoCount(bool, defaultstrue) sits before it in the signature, and a bare positional token there fails to compile- Always
.ConfigureAwait(false)on everyawait
For full workflow and code examples see `references/workflow.md`.
Key References
- `/.github/instructions/coreex-repositories.instructions.md` — full conventions: EfDb, DbContext, mappers, query config, adapters
- Related skills: `coreex-db-migration` (generates the persistence models this maps), `coreex-app-service` + `coreex-adapter` (consumers), `coreex-aggregate` (persisting aggregates)
- Illustrative examples (CoreEx sample — not present in your project):
- contract-mapping repositories —
ProductRepository(CRUD + query),ProductsEfDb,ProductsDbContext— and BiDirectionMapper (ProductMapper) - Domain-mapping repositories —
BasketRepository(Result<T>+ Domain mapping) — and one-way Domain ↔ Persistence mappers (BasketMapper)
- contract-mapping repositories —