Repositories
repository: adds query methods to an entity's Spring Data repository. The key is the entity
name, and the methods are a methods: list.
repository:
Stock:
methods:
# derived query - no query, the method name says it
- id: findByItemItemCodeAndWarehouse
params:
itemCode: string
warehouse: string
return: Optional<Stock>
# JPQL
- id: findLowStock
params:
threshold: int
return: List<Stock>
query: "SELECT s FROM Stock s WHERE s.onHand < :threshold ORDER BY s.onHand"
# paging
- id: findByWarehouse
params:
warehouse: string
return: Page<Stock>
pageable: true
| Key | Means |
|---|---|
id | the method name |
params | parameters (name: DSL type) |
return | List<Entity>, Optional<Entity>, Entity, Page<Entity>, long, a DTO ... |
query | JPQL; without it a Spring Data derived query |
nativeQuery: true | native SQL |
pageable: true | a Pageable as the last parameter |
An entry without a methods list (methods written as keys) is not read: the generator warns and
skips it.
Read models: projections to a DTO
Screens and reports read DTOs, not aggregates. Write the return type as a DTO and match the column aliases to its properties:
repository:
SalesOrder:
methods:
- id: summarizeByPartner
params: { status: OrderStatus }
return: List<PartnerSalesDTO>
query: "SELECT o.partner.partnerId AS partnerId, o.partner.name AS partnerName, COUNT(o) AS orderCount, SUM(o.totalAmount) AS totalAmount FROM SalesOrder o WHERE o.status = :status GROUP BY o.partner.partnerId, o.partner.name"
On v3 and Kotlin the repository returns List<Tuple> and the query port List<PartnerSalesDTO>: the
adapter fills the properties from the aliases (ignoring case and underscores, converting types). A
column without an alias is an error. The 2.x-compatible output keeps List<Object[]>.
In the DDD and hexagonal bundles
| Declared | Goes to | Why |
|---|---|---|
a lookup returning Root / Optional<Root> / List<Root>, not paged | RootRepositoryPort (domain) | a domain service finding aggregates |
everything else (Page, DTO projections, counts, modifying queries) | RootQueryPort (application) | screens and reports, or bulk writes past the aggregate |
// StockRepositoryPort (generated)
Optional<Stock> findByItemItemCodeAndWarehouse(String itemCode, String warehouse);
Preserved blocks
Code that has to live in a generated repository goes in one preserved block, right before the class's closing brace; it survives regeneration:
// !-----------------------------------------------------------
@Query("SELECT e FROM Entity e WHERE e.name = :name")
List<Entity> findByName(@Param("name") String name);
// ------------------------------------------------------------!
SQL outside JPA - native reports, other datasources - is a DBMS port.