* DB2 exists - use existsWithCaseWhen true, similar to #3849
Fixes exists() query regression with DB2 by using the platform flag existsWithCaseWhen = true;
* DB2 using existsFromClause = " from sysibm.sysdummy1";
---------
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
* Add FinableQuery, StreamableQuery common interfaces for Query, DtoQuery, MappedQuery, SqlQuery
* QueryBean.cancel() added to support the new common FindableQuery interface
---------
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
Adding this as I am seeing a LOT of cases where ebean can derive a good enough
error message (id case, plus single unique key case) that it is worth adding
this syntax sugar.
Yes we have discussed this a well it's not so useful for the multi-lingual /
non-english case and also marginal when the error message needs to be built
case.
When a *ToOne association is fetched with only its id property, the
foreign key column already exists on the owning table so no join is
required. Previously this always generated an unnecessary join.
- OrmQueryProperties: add includesExactly() and withAddedInclude() to
support adding an include without mutating a shared/cached instance
(the included set and its precomputed hash prefix are immutable
since #3761/#3763, so an "add" must produce a new instance).
- OrmQueryDetail: add convertIdFetches(), a bottom-up pass over
fetchPaths that replaces an id-only *ToOne fetch with its FK
property folded into the parent's select, removing the now-unneeded
fetch path. Skips exported (mappedBy) one-to-one associations, which
have no local FK column and always require a join. Tracks paths
still depended on by a surviving child fetch so their join isn't
incorrectly folded away.
- Add TestFetchIdOnly covering PathProperties, select(), and fetch()
usages, plus a control case confirming the join is retained when
more than the id is fetched.
- Update EqlParserTest, TestSubQuery and TestMergeCustomer assertions
to reflect the new join-free SQL.
Fix#2 — @DtoRef never checked hasField(): Added requires() to @DtoRef
(same explicit-empty semantics as @DtoPath). DtoMappingReader now
detects a computed association getter and requires an explicit
requires(); DtoMapperWriter's REF case routes computed segments
through extraFetchPaths instead of a broken select(assoc).
Fix#3 — requires() values never validated: Added DtoMappingReader.validateRequiresPath(...), walking every requires() segment against the real property graph (with List unwrapping via a new getterReturnTypeMirror helper). A typo now fails at compile time instead of resurfacing as a runtime PersistenceException. New negative
Fix#4 — bare requires() fetch vs narrowed sibling @DtoPath fetch collision: Traced into Ebean's OrmQueryDetail.fetch(...) and confirmed same-path fetch calls replace, not merge (Map.put). The old dedup logic had priority backwards, silently letting a narrow selection win and drop a computed getter's real dependency. Fixed by prioritizing the full fetch. Proved the regression test was meaningful by reverting the fix and confirming it fails with LazyInitialisationException: Property not loaded: line1, then restored the fix and confirmed it passes.
* Version 18.3.0
* InsertOnConflict - change to exclude non-updatable and generated on insert only (e.g. @WhenCreated)
---------
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
* #2540 Add DTO mapping from Entity beans via generated mapper code
A large feature, refer to the docs / guides etc. This is a bit like MapStruct in that it generates mapping code via annotation processing but it ALSO creates an optimised FetchGroup for the destination DTO graph and it also implements a generic interface such that it can be fluently used via query.mapTo().
The value is that it automates the mapping code from entity -> dto plus optimises the query used to support building the DTO graph.
Expected to be better to use than MapStruct for ebean orm users.
* Bump ebean-annotation to 8.6 with the dto annotations
* Adjust the build order to via test dependency on ebean-api
---------
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
* Bug: filterMany() expressions when additional nested fetch has predicates in wrong place
When a filterMany() expression only references the many-root's own properties (e.g. .eq("status", ...)),
but the query also has an additional nested fetch beneath that many-path (e.g. .fetch("orders.customer")
or .fetch("contacts.group")), the filter predicate was incorrectly attached to the last/deepest join's
ON clause instead of the many-root's own join — silently misapplying the filter.
Fix: A hybrid approach:
- If the filterMany expression references only root-level properties → attach the predicate directly on the many-root's own join (correct).
- If it references deeper/nested properties requiring "extra joins" (a separate existing mechanism) → fall back to the original end-of-subtree behavior, since no SqlTreeNode exists to attach to.
- includeFilterMany() made idempotent so both mechanisms coexist safely.
* Bug: filterMany() with nested-property predicates silently ineffective
filterMany() expressions referencing a nested/dotted property (e.g.
.eq("group.name", "x"), alone or mixed with root properties) were
attached to a LEFT JOIN's ON clause via the "extra join" mechanism.
That only nulls the extra join's own columns on non-match - it does
not exclude the parent/many-side row, so the predicate had no actual
filtering effect (confirmed by data, not just SQL shape).
## Fix:
force any many-property fetch whose filterMany expression
references a nested property onto a query-join (secondary select
restoring filterMany's original always-fetchQuery behaviour for this
with a genuine WHERE clause) instead of leaving it as an inline JOIN, case.
- SpiExpressionValidation: track all visited property names (allProperties()), not just unknown ones.
- OrmQueryProperties: filterManyHasNestedProperty() walks the filterMany expression for any dotted property reference.
- OrmQueryDetail.markQueryJoins(): route nested-property filterMany chunks to markForQueryJoin() instead of the inline fetch-join slot, without consuming that slot for other many-paths.
Also simplifies the earlier root-only-predicate join-placement fix
(CQueryPredicates/DefaultDbSqlContext/SqlTreeNodeManyRoot) now that
a nested-property filterMany can never reach the JOIN-based code
path: removed the now-unreachable "deepest path" fallback branch,
the includeFilterMany() idempotency guard, and the redundant fallback
call in SqlTreeNodeManyRoot - isFilterManyAttachPoint() remains as
the single, always-used attach mechanism.
Updated TestQueryFilterMany/TestQueryFilterManySimple assertions to
expect the corrected query-join (2 statement) behaviour.
* Simplify SpiExpressionValidation with boolean nestedProperty flag
* Tidy up comments
* Fix OrmQueryProperties.filterManyHasNestedProperty() with real nested property check
---------
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>