Easy Query ORM
Write compilable easy-query code from verified patterns.
Use this file only as the router. Open one primary reference first. Add at most one secondary reference when a boundary rule below says it is needed.
Operating Rules
- Default to
EasyEntityQueryand proxy DSL unless the project clearly uses weak-typedEasyQueryClient. - Treat
eqin user requests, docs, or code comments as a common shorthand foreasy-queryunless surrounding project context clearly proves otherwise. - Missing
*Proxyusually means setup or compile-chain trouble first. Java uses APT via thesql-processorannotation processor artifact; Kotlin uses KSP via thesql-ksp-processorartifact, not KAPT. WhenannotationProcessorPathsis already configured, the corresponding processor artifact must appear there explicitly. Having the easy-query dependency on the compile classpath alone is not enough for the processor to fire. @EntityProxyis the generation trigger.ProxyEntityAvailablehelps with typed proxy usage but is not the switch that makes APT/KSP generate the class.- For proxy-generation failures, diagnose by layer: generation mode,
processor wiring, generated output path, then the first real compile error.
Do not stop at
package xxx.proxy does not exist. - Never invent easy-query API names. Search
references/api-map.mdorscripts/search_references.pyfirst. - If code, docs, or a user snippet mention easy-query type names without
imports, resolve the package from
references/symbol-imports.mdfirst. Do not guess the package from memory. 7a. When multiple candidate files are given, grep for key question terms across the candidate set first to identify the relevant file and line range, then read only the targeted span around the match rather than loading entire documents. 7b. For identifier-only questions, answer with only the direct invocation identifier or exact call shape. Prefer the callable method or exact builder-chain call the user should invoke, not the backing class, interface, or generator name. - For AP/reporting work, keep dimensions, grouped aggregates, partition
ranks, and union branches in SQL DSL. Prefer explicit
groupBy/havingfirst; switch tosubQueryToGroupJoinwhen repeated to-many relation metrics would otherwise emit many correlated subqueries. - easy-query leans heavily on relation metadata. If the requirement can be
derived from an existing relation path, prefer the relation-driven form
first: implicit navigation,
flatElement, relation aggregate/predicate. For tree answers, express the real root rule first, then apply recursive filtering or ancestor backfill only where needed. Fall back to explicit join, junction-table query, or post-query assembly only when the needed@Navigatepath is missing or clearly insufficient. - Prefer gated DSL for optional filters. Use
whereObject(...)only for search-form DTOs. - Keep paging stable with explicit
orderBy(...)and a tie-breaker. - Treat row count
0as meaningful. - Distinguish entity relation metadata from DTO/VO auto-include metadata.
- Distinguish transient business fields, ignored ORM fields, and true SQL-derived computed properties; do not collapse them into one pattern.
- For derived fields/metrics, let project context, prompt semantics, likely reuse, and complexity of the equivalent query shape guide the choice between entity-side computed-property modeling and query-time projection.
- Split typed SQL expression questions from raw SQL questions, but keep the
boundary honest:
typed-sql-expressions.mdis the typed SQL expression layer, still SQL-side and still subject to dialect/version support;native-sql.mdis the handwritten SQL escape hatch for fragments, wrappers, and fallback entrypoints when the typed surface is insufficient. When the needed string/date/math/JSON capability already exists in the typed surface, explicitly say to stay inreferences/typed-sql-expressions.md. The answer should say: do not recommend raw SQL first. - If the project version differs from the reference version, prefer the project and say which API or behavior may have moved.
Triage
- Classify first: setup/runtime, mapping/modeling, query/search, relation/implicit, write/cross-cutting, AP/reporting, troubleshooting, or review.
- Open one primary reference from
Routing Table. - Add one secondary reference only when a
Pair with ...clause applies. - Use
references/symbol-imports.mdfirst when the missing piece is the package/import/FQCN for a type name. - Use
references/api-map.mdwhen the exact symbol exists but the right semantic reference or verified API surface is still unclear. - Use
references/troubleshooting.mdonly after a primary feature reference is already known, or when code compiles but behaves differently from the expected feature semantics.
High-Conflict Boundaries
- Spring Boot:
setup-spring-boot.mdis dependency/basic wiring;spring-boot-starter.mdis starter internals, collected beans, andStarterConfigurer;configuration-starter.mdis property semantics;advanced.mdis DDL/sharding/runtime scope. - Modeling:
entity-mapping.mdis basic entity/proxy mapping;entity-modeling-advanced.mdis advanced table/column flags;primary-key-generation.mdis key strategy and timing;relation-query.mdis entity relation shape;entity-modeling-navigate.mdis advanced/DTO-side navigation metadata;include-structured-loading.mdis entity include loading;select-auto-include.mdis DTO graph return. - Query:
query.mdis ordinary root DSL;query-composition.mdis explicit joins/projection/proxy VO.set(...);subquery-explicit.mdis explicit subquery/derived table/CTE promotion;implicit-query.mdandimplicit-controls.mdare relation-driven SQL;typed-sql-expressions.mdis typed SQL expressions and typed database functions;native-sql.mdis raw SQL fragments, raw SQL entrypoints, and fallback database-function writing. - Search form:
search-form-page.mdis endpoint workflow;dto-object-query.mdiswhereObject/orderByObject/@EasyWhereCondition;easy-search.mdis only forsql-search. - Write vs savable:
write*.mdis ordinary row mutation;primary-key-generation.mdis key strategy rather than generic insert syntax;savable-aggregate.mdis only for aggregate diff save.
Routing Table
Setup & Runtime
- Missing
*Proxy,package ...proxy does not exist, APT/KSP not firing, generated-sources visibility,annotationProcessorPaths,javacTree, Lombok/JDK processor crashes:references/proxy-generation-troubleshooting.md. Pair withreferences/setup-java.md,references/setup-kotlin.md, orreferences/setup-spring-boot.md. - Plain Java + Maven/APT wiring and manual bootstrap:
references/setup-java.md. - Kotlin + Gradle + KSP wiring:
references/setup-kotlin.md. - Spring Boot dependency/basic wiring/client injection:
references/setup-spring-boot.md. Pair withreferences/spring-boot-starter.mdonly for starter internals. - Spring Boot starter topology,
EasyQueryInitializeOption,StarterConfigurer, collected extension beans,@EasyQueryTrack, multi-datasource starter limits:references/spring-boot-starter.md. Pair withreferences/configuration-starter.mdonly for property impact. - Spring Boot multi-datasource, multiple
EasyQueryClientbeans, baomidouDynamicRoutingDataSource,@DS, or@EasyQueryTrack(tag=...)across several clients:references/multi-datasource.md. Pair withreferences/spring-boot-starter.mdwhen the answer also depends on starter internals or collected extension beans. - Starter defaults,
easy-query.enable/easy-query.build, or behavior drift from code:references/configuration-starter.md. - Code-first DDL, sharding, multi-datasource runtime scope:
references/advanced.md.
Mapping & Result Shape
- Entity annotations,
@EntityProxy,@Column,@Version,@LogicDelete:references/entity-mapping.md. - Advanced table/column modeling such as
@EasyAlias,@TableIndex,@ColumnIgnore,@InsertIgnore,@UpdateIgnore,primaryKeyGenerator,generatedSQLColumnGenerator,schema,oldName, or@EntityFileProxy:references/entity-modeling-advanced.md. - Primary key generation strategy such as
generatedKey,generatedSQLColumnGenerator,primaryKeyGenerator, insert id backfill, or starter/manual generator registration:references/primary-key-generation.md. Pair withreferences/write-insert-upsert.mdwhen the question also depends onexecuteRows(true)or insert-chain behavior. - Computed/derived properties such as
sqlExpression,sqlConversion, cross-table computed fields,autoSelect=false, or current@ValueObjectusage:references/entity-computed-properties.md. - Fix
@Navigatecardinality/direction or a missing relation path:references/relation-query.md. Tree/self-relation entity modeling also starts here. - Advanced relation metadata, DTO-side navigation,
@NavigateFlat,@IncludeOnProperty, navigate extras:references/entity-modeling-navigate.md. - Entity graph loading with
include,include2,loadInclude,fillOne/fillMany:references/include-structured-loading.md. - DTO/VO structured return with
selectAutoInclude, extras, and include override precedence:references/select-auto-include.md.
Read Query & Search
- Ordinary filter/order/select/page/terminal query chains:
references/query.md. - Pessimistic row-level locking with
forUpdate(), transaction and single-table requirements, nested-query scope, and dialect support:references/query-locking.md. Pair withreferences/transaction.mdwhen the transaction boundary is also part of the answer. - Explicit joins, advanced projection, draft/tuple, or proxy VO relation
.set(...):references/query-composition.md. - Explicit
where/select/from/joinsubquery,exists/notExists/in/notIn,expression().subQueryable(...),setSubQuery(...), derived table, ortoCteAs():references/subquery-explicit.md. Pair withreferences/implicit-query.mdonly when a relation-driven alternative orsubQueryToGroupJoin(...)tradeoff matters. - Implicit relation capabilities: implicit join, scalar subquery, group join,
ranked child, tree:
references/implicit-query.md. - Quantifiers and relation control knobs such as
any/all/none/notEmptyAll/subQueryConfigure/filter/configure/mode/flatElement/valueOf:references/implicit-controls.md. Pair withreferences/implicit-query.mdwhen partition/tree/group-join behavior matters. - AP/reporting, grouped aggregates, conditional metrics, CTE/window, UNION:
references/ap-analytics.md. Pair withreferences/implicit-query.mdfor repeated to-many relation metrics or relation-derived dimensions. - Search/page form endpoints with optional filters, stable sort, and DTO graph
return:
references/search-form-page.md. whereObject(...),orderByObject(...),@EasyWhereCondition, relation-path filters,ObjectSortBuilder,WhereObjectQueryExecutor:references/dto-object-query.md.EasySearch,@EasyCond,sql-searchoperator inference:references/easy-search.md.
Functions & Native SQL
- Typed SQL expressions such as string/number/date/JSON capabilities,
valueConvert, casts, path access, and typed database-function writing such asconcat/ date functions / math functions / JSON functions:references/typed-sql-expressions.md. - Raw SQL entrypoints, fragments, wrappers, and dialect fallback for database
functions that are not already exposed by the typed surface:
references/native-sql.md.
Write & Cross-Cutting
- Mutation overview, write-path selection, and batch execution semantics:
references/write.md. - Insert/upsert/map insert/insert
columnConfigure(...):references/write-insert-upsert.md. - Update/object update/map update/
setColumns/setIgnoreColumns/whereColumns/optimistic lock:references/write-update.md. - Delete / physical delete safety / version-aware delete / expression delete vs
object delete:
references/write-delete.md. - Diff update tracking /
TrackManager/asTracking/addTracking/@EasyQueryTrack:references/write-tracking.md. - Plain transaction API or Spring
@Transactional:references/transaction.md. - Aggregate graph save with
savable(...), including@SaveKeynon-PK matching for many-to-many middle tables:references/savable-aggregate.md. - If the savable question is explicitly about execution preconditions,
savePath, root controls, ownership/cascade,@SaveKeybusiness-key matching, or child key safety, start atreferences/savable-aggregate.mdand follow its router instead of opening all savable references at once. - Value conversion, auto conversion, enum/json mapping, enum-
name()mapping via@Enumerated,JdbcTypeHandler, PostgreSQLjsonb:references/value-conversion-type-handler.md. - Interceptors, tenant/audit/data-permission,
useInterceptor(...)/noInterceptor(...):references/interceptor.md. - Logic delete strategies, toggles, table-local disable, physical delete
escape hatch:
references/logic-delete.md.
Support
- Missing import / package / FQCN for an easy-query type:
references/symbol-imports.md. - Exact symbol surface or "does this API name exist":
references/api-map.md. - Unit test shapes for repositories/services or SQL-shape assertions:
references/testing.md. - Common non-obvious failure modes after the primary feature path is already
known:
references/troubleshooting.md.
Review Checks
- Reject non-easy-query syntax unless the task is explicit migration.
- Prefer relation-driven answers before explicit join or link-table queries when
an existing
@Navigatepath can express the requirement. - Do not casually introduce
@ValueObjectfor new modeling without noting that current source marks it deprecated. - For derived fields/metrics, do not force either extreme: neither sink every simple aggregate into entity computed properties nor rule modeling out when reusable model-level meaning is reasonably likely.
- For tree answers, express the real root predicate first instead of teaching a
default
query ids first -> .in(...) -> build treetemplate. - Prefer
singleOrNull()for unique business keys. - Push filter/sort/page/aggregate work into DSL.
- Treat
forUpdate()as a pessimistic row lock: it requires an active transaction, is applied once to a single-table root query in 3.2.15, and varies by dialect. Do not present it as a replacement for@Versionor claim that nested subqueries are locked by the outer query. - Use DTO/VO result types for
selectAutoInclude, not database entity classes. Explain that nested child data is fetched by separate include-style relation queries per relation path, not by a single joined SQL statement. - For
selectAutoInclude, distinguish root filtering from child-list pruning: use root.where(...)for root eligibility, and preferEXTRA_AUTO_INCLUDE_CONFIGURE.where(...)when child rows should be pruned while the root row stays. - When a child filter/projection is part of the DTO contract itself, prefer
EXTRA_AUTO_INCLUDE_CONFIGUREover scattering one-offinclude(...)adapters across service methods. - Prefer
include2for more complex nested relation loading. - Do not claim
ProxyEntityAvailableis required for proxy generation unless the project specifically requires interface mode for usage style. - For AP/reporting answers, prefer DSL aggregation / CTE / UNION / partition APIs over Java Stream regrouping, manual SQL strings, or post-query in-memory metrics.
- For aggregate-only multi-metric projections, prefer the no-argument
groupBy()path withAggregateQueryableandSelect.DRAFT. For one whole-result scalar, prefer the matching aggregate terminal such assumOrNull(...)ormaxOrNull(...). UseGroupKeys.of(...)only when actual grouping dimensions must be projected. - For typed SQL expression questions, keep the answer inside the typed surface and do not drift into raw SQL fragment advice unless that surface is truly missing.
- For native SQL answers, do not jump straight to
sqlQuery(...)if the raw SQL is only theFROMseed and the rest should still use easy-query DSL; preferqueryable(rawSql, Entity.class, params)in that case. - Prefer current-source proxy native-fragment names
rawSQLCommand(...)andrawSQLStatement(...)over olderexpression().sql(...)/expression().sqlSegment(...)compatibility forms unless the project code already uses the older surface or the answer specifically needs lower-levelformat(...)/messageFormat()control. - When recommending raw SQL fragments, distinguish JDBC parameters
value(...)from literal insertionformat(...), and mentionmessageFormat()/ keep-style quoting if the SQL template itself contains quoted literals plus placeholders. - Keep grouped projections group-aware: non-key fields should come from aggregate expressions, grouped proxy access, or explicit window outputs.
- Do not narrow
elements(start,end)to string concatenation only; current source returnsSQLQueryableafterelements(...), so ranked-window slices can continue into aggregate or predicate chains when the API surface fits. - Distinguish expression update from object update; do not blindly answer
every update request with
updatable(entity).executeRows(). - Distinguish expression delete from object delete; do not collapse
deletable(Entity.class)anddeletable(entity)into one generic delete shape. - Do not rewrite valid relation-driven expression update/delete into query-then-loop or query-ids-then-delete flows without a dialect-specific reason.
- When using
updatable(entity).setColumns(...), mentionwhereColumns(...)when the write condition must stay explicit. - Do not claim
asTracking()alone enables diff update; explicitly mention an active tracking context (@EasyQueryTrackor manualTrackManager.begin()), and explicitly mention the tracked entity requirement: the tracked entity itself must have been added to the active tracking context viaasTracking()oraddTracking(...). - Do not explain
savable(...)as if transaction or track context were optional; current source requires both before execution, and the root or child entities being diff-saved must also be in the active tracking context. - Do not teach
savable(...)as a generic recursive save for aggregate-root navigations such as many-to-one parent objects. - Do not recommend
ALLOW_OWNERSHIP_CHANGEcasually; it changes ownership safety semantics. - Do not recommend
onConflictThen(...)without calling out constraint-column selection semantics and theALL_COLUMNScaveat when conflict columns may be omitted by strategy. - For map writes, keys are column names, not entity property names.
- Do not trust batch affected-row counts as exact business success across all drivers.
- State
batch()semantics precisely:batch()equalsbatch(true), it enables the JDBC batch execution path for the current chain, andbatch(false)disables it. - For correlated explicit subqueries, prefer
expression().subQueryable(...)over an independently created root query unless detached composition is intentional. - Do not leave a bare subquery type fragment in
where(...); end it asexists,notExists,in,notIn, or scalar comparison. - Do not recommend
JdbcTypeHandlerwhen an in-memoryValueConverteris sufficient. - Do not recommend
ValueConverteralone when the real problem is JDBC binding/driver behavior such as PostgreSQLjsonbPGobjectwrites. - For enum-by-name mapping, prefer the built-in
@Enumeratedon the enum type (it is@Target(TYPE), registered globally viaNamedEnumValueAutoConverter, storesname()as a varchar, and needs no per-field@Column). Do not put@Enumeratedon the entity field; it has no effect there. For numeric/code enums keep theIEnum+ValueConverterpath and do not add@Enumeratedto those enums. An explicit@Column(conversion = Xxx.class)on a field still overrides the@Enumeratedauto converter for that field only. - Do not conflate
generatedKey,generatedSQLColumnGenerator,primaryKeyGenerator, andsaveEntitySetPrimaryKey(...); they solve different phases of key assignment. - For
savable(...)many-to-many middle tables whose rows should match by a business composite key (e.g.(rootId, manyId)) rather than a surrogate PK, put@SaveKey(com.easy.query.core.annotation.SaveKey,@Target(FIELD)) on those fields. It is an in-memory matching identity used only inside the savable diff — it does NOT change generated SQLWHERE/SET(still PK-based) and has no effect on directinsertable/updatable/deletable. Do not confuse it withsaveEntitySetPrimaryKey(...)(backend PK assignment for untracked children); they are orthogonal. Seesavable-relation-rules.md§5.5. - Do not teach
executeRows(true)as if Java-sidePrimaryKeyGeneratorneeded it. - Prefer interceptor abstraction for cross-cutting tenant, audit, and data-permission rules instead of repeating ad hoc where/set logic in every service.
- State
useInterceptor(...)/noInterceptor(...)semantics precisely:useInterceptor(name)does not mean “only this one”, andProtectedInterceptorsurvives globalnoInterceptor()unless removed bynoInterceptor(name). - Separate soft-delete semantics from physical delete semantics; do not teach
disableLogicDelete()as a harmless default. - Mention
tableLogicDelete(...)for a joined table and relation.configure(q -> q.disableLogicDelete())for a relation path when only part of a query graph should ignore logical delete. - Do not assume outer logic-delete toggles or arbitrary custom
ValueFilterautomatically propagate to independent explicit subqueries. - For Spring Boot starter answers, do not claim
easy-query.enable: trueis mandatory unless the project version proves a different condition implementation. Botheasy-query.enableandeasy-query.buildconditions usematchIfMissing=true, so the property being absent keeps the auto-configuration enabled by default. Only setting the property tofalseexplicitly disables the corresponding behavior. Preferreferences/configuration-starter.mdfor version-specific details. - For Spring Boot extension registration, do not claim a plain
JdbcTypeHandlerbean auto-binds globally; mentionJdbcTypeHandlerReplaceConfigurer. - For Spring Boot multi-datasource answers, remember that the default starter
build path injects a single
DataSource; recommend@Primaryonly when one default client is acceptable, otherwise use custom beans oreasy-query.build=false. - Do not present doc-demo wrapper types such as
EasyMultiEntityQueryas built-in framework APIs unless the project itself defines them. - When non-obvious easy-query types appear in code or explanation, include an import line or FQCN on first mention if the original snippet omitted it.
- Always resolve the exact package from
references/symbol-imports.md; never construct or guess the FQCN from partial domain knowledge or inferred package hierarchy.
Evidence Policy
Order of truth:
- Current project state.
- Verified patterns in these references.
- If neither covers the case, say so plainly instead of inventing API.
If the project version differs from the reference version, prefer the project and flag APIs that may have moved.
Output
Lead with working code. For troubleshooting, lead with the first failing layer
and the next concrete check or fix. For AP/reporting, state the
dimension -> metric -> filter -> rank/union/cte shape before dropping into
code when that framing prevents wrong SQL structure. Cite a reference only for
non-obvious API, SQL-shape, or version caveat.
- If the question is identifier-only, such as "which API", "what method", "name the property", or "what exact call", override the code-first rule and answer with only the direct invocation identifier or exact call shape, then stop. Prefer the callable method or exact builder-chain call over a backing class, interface, or generator name when the user is asking what to invoke. Do not add code blocks, FQCNs, import lines, package paths, signatures, parameter lists, usage examples, documentation references, or extra explanation unless the user explicitly asks for "how", "why", or "explain".
If compile-ready code uses non-obvious easy-query annotations, enums, starter SPI, or extension types, include the needed imports instead of assuming the reader can recover them from context.
For true physical delete when logic delete is active, both
disableLogicDelete()andallowDeleteStatement(true)are required; do not omit the latter.In tree CTE answers, distinguish anchor/seed filtering from recursive-member filtering: outer
.where(...)before.asTreeCTE(...)filters only the seed rows; usesetChildFilter(...)or equivalent tree CTE config to control the recursive step.When a question directly targets a boundary rule or review check already stated in this file, answer directly from that guidance and answer directly without opening external reference files. Use the exact phrasing from the review check as the authoritative source; do not paraphrase or substitute entity/type names. Only open a reference when the question needs API-level detail, code examples, or deeper explanation beyond what the review checks state.
When the question asks what the skill recommends, enforces, warns against, or should say, quote the relevant review-check wording directly in the answer, including negatives such as
do not,not,without, orrequires both, rather than paraphrasing.When a question mentions a type name or asks for its import, include the actual import line or FQCN in the answer from
references/symbol-imports.md; do not defer to the reference for that concrete value.Use exact artifact names, property names, and API identifiers as written in the skill and references; do not reword or generalize them.
When a navigation should load only for certain root rows based on a static entity property (e.g., version), prefer the entity-side annotation
@IncludeOnPropertyon the@Navigatefield. Do not drift into DTO child filtering viaEXTRA_AUTO_INCLUDE_CONFIGUREas the first approach; note thatEXTRA_AUTO_INCLUDE_CONFIGUREis a query-time DTO child-list pruning knob, not an entity metadata gating mechanism. Also, note thatloadInclude(...)evaluates already-loaded root objects in memory before issuing relation queries, so entity-side@IncludeOnPropertymetadata still applies toloadIncludecalls. Route toreferences/entity-modeling-navigate.mdfor entity-side conditional navigation.For
selectAutoInclude, always preserve the DTO/VO class literal in the call (e.g.,selectAutoInclude(ResultDTO.class)). Do not substitute a different class name or omit the class argument; without the class literal, easy-query cannot determine which nested relations to include.When the task, context, or eval surface names an exact API call shape with type parameters or arguments (for example,
selectAutoInclude(ResultDTO.class)), reproduce the full call expression including generic type arguments rather than naming only the bare method; do not abbreviate to a method-only form.When the question asks for an exact call shape, or when an argument value is what makes the API semantically correct, include the necessary argument value instead of truncating to the bare method name. For example,
allowDeleteStatement(true)is materially different fromallowDeleteStatement(), andqueryable(rawSql, Entity.class, params)is more precise than a barequeryable.For identifier-only questions (e.g., "which method", "what property", "name the API"), the answer must be only the identifier or exact call shape, without code blocks, explanation, or extra context. Do not include the class name, package, or usage example unless explicitly asked.