Not the best issue but let me know if you encounter any problem:

https://github.com/apache/grails-core/issues/15589


Gianluca Sartori
--
https://dueuno.com


On Tue, 21 Apr 2026 at 13:48, James Fredley <[email protected]> wrote:

> Yes, please create an issue with test project.
>
> James
>
> On 2026/04/21 08:01:32 Gianluca Sartori wrote:
> > Hi James,
> >
> > I'm trying the alias because the code below was not working:
> >
> > if (filterParams.containsKey('workPackage.code')) query = query.where
> > { workPackage.code == filterParams.'workPackage.code' }
> >
> > This neither:
> >
> > if (filterParams.containsKey('workPackage.code')) query = query.where {
> >     workPackage {
> >         code == filterParams.'workPackage.code'
> >     }
> > }
> >
> >
> > This is the exception:
> >
> > Caused by: org.hibernate.QueryException: could not resolve property:
> > workPackage.code of: momentum.work.TWorkAssignment
> > at
> >
> org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:78)
> > at
> >
> org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:93)
> > at
> >
> org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:43)
> > at
> >
> org.hibernate.persister.entity.AbstractEntityPersister.toColumns(AbstractEntityPersister.java:2023)
> > at
> >
> org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumns(CriteriaQueryTranslator.java:566)
> > at
> >
> org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumnsUsingProjection(CriteriaQueryTranslator.java:495)
> > at org.hibernate.criterion.Order.toSqlString(Order.java:109)
> > at
> >
> org.hibernate.loader.criteria.CriteriaQueryTranslator.getOrderBy(CriteriaQueryTranslator.java:440)
> > at
> >
> org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:106)
> > at
> >
> org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:75)
> > at
> >
> org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:80)
> > at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1908)
> > at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:370)
> > at
> >
> org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:827)
> > at
> >
> org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:817)
> > at grails.gorm.PagedResultList.<init>(PagedResultList.java:50)
> > at
> >
> grails.gorm.DetachedCriteria$_list_closure2.doCall(DetachedCriteria.groovy:141)
> > ...
> >
> > I can provide a test project to reproduce the case if you need it
> >
> > Gianluca
> >
> >
> > Gianluca Sartori
> > --
> > https://dueuno.com
> >
> >
> > On Mon, 20 Apr 2026 at 22:22, James Fredley <[email protected]>
> wrote:
> >
> > > Hi Gianluca,
> > > Thank you - this is exactly the pattern I was hoping to see laid out
> > > end-to-end. A few thoughts and one follow-up question.
> > >
> > > 1) Your shape is effectively the real-world case for PR #15447
> > > (apache/grails-core):
> > >     def query = TWorkAssignment.where {}
> > >     if (filterParams.containsKey('id')) query = query.where { id ==
> > > filterParams.id }
> > >     if (filterParams.containsKey('workPackage')) query = query.where {
> > > workPackage.id == filterParams.workPackage }
> > >
> > > Prior to that fix, DetachedCriteriaTransformer only visited
> > > DeclarationExpression, so every query = query.where { ... }
> re-assignment
> > > was silently skipped by the AST transform. At runtime the untransformed
> > > closures evaluated to non-mutating clones and buildQuery would have
> > > returned every TWorkAssignment regardless of filterParams. Adding
> > > visitBinaryExpression fixed that. Your reply confirms the fix covers
> the
> > > canonical "empty initial where + chained reassignment under if-guards"
> > > idiom, which is good to see.
> > > 2) One specific question on the alias line:
> > >     if (filterParams.containsKey('workPackage.code')) query =
> query.where {
> > >         def wp = workPackage
> > >         wp.code == filterParams.'workPackage.code'
> > >     }
> > > The GORM reference documents the explicit-alias idiom (def wp =
> > > workPackage) primarily for sorting/projection (.list(sort:
> 'wp.code')), but
> > > you are using it here purely for a filter. Is there a specific case
> where
> > > the direct form:
> > > workPackage.code == filterParams.'workPackage.code'
> > > misbehaves, and the aliased form rescues it? Or is this stylistic /
> > > defensive?
> > > If you have hit a real transformer or scope issue with the direct form,
> > > would you be willing to open an issue on apache/grails-core (or a PR
> if you
> > > already have a fix in mind)? It would be useful to track it alongside
> > > #15447/#15448 rather than leave it as tribal knowledge.
> > > If it is stylistic rather than a bug, would you consider contributing
> this
> > > pattern directly to the Grails documentation - specifically the GORM
> "Where
> > > Queries" section (
> > > https://grails.apache.org/docs/latest/guide/GORM.html#whereQueries)?
> The
> > > existing docs cover basic property comparison and associations but do
> not
> > > describe composing conditional filters via chained re-assignment, the
> > > flat-map-with-dotted-keys convention, or the aliased form for
> > > nested-property filtering. From your Medium article and this reply, the
> > > rules that emerge are:
> > >   - @CompileStatic on the class, @CompileDynamic on the buildQuery
> method
> > >   - Accept a Map filterParams; do not name local variables after domain
> > > properties
> > >   - Start with an empty where {} and chain conditional query =
> query.where
> > > { ... } re-assignments
> > >   - Flat-map-with-dotted-keys for nested filters:
> > > filterParams.'workPackage.code'
> > >   - FK shortcut for simple association filters: workPackage.id ==
> > > filterParams.workPackage
> > >   - Aliased association access for nested-property filters: def wp =
> > > workPackage; wp.code == ...
> > >
> > >
> > > James
> > >
> > > On 2026/04/20 10:42:29 Gianluca Sartori wrote:
> > > > Hi James,
> > > >
> > > > this is the query:
> > > >
> > > >     @CompileDynamic
> > > >     private DetachedCriteria<TWorkAssignment> buildQuery(Map
> > > filterParams) {
> > > >         def query = TWorkAssignment.where {}
> > > >
> > > >         if (filterParams.containsKey('id')) query = query.where { id
> > > > == filterParams.id }
> > > >         if (filterParams.containsKey('workPackage')) query =
> > > > query.where { workPackage.id == filterParams.workPackage }
> > > >         if (filterParams.containsKey('workPackage.code')) query =
> > > query.where {
> > > >             def wp = workPackage
> > > >             wp.code == filterParams.'workPackage.code'
> > > >         }
> > > >
> > > >         return query
> > > >     }
> > > >
> > > >
> > > > Thank you for your time,
> > > > Gianluca
> > > >
> > > > Gianluca Sartori
> > > > --
> > > > https://dueuno.com
> > > >
> > > >
> > > > On Sat, 18 Apr 2026 at 02:43, James Fredley <[email protected]
> >
> > > wrote:
> > > >
> > > > > Can you share buildQuery? The def o1 = owner AST trick requires the
> > > > > literal Domain.where { ... } form; if your builder composes
> criteria
> > > > > programmatically, the alias won't be registered and the sort will
> > > silently
> > > > > drop.
> > > > >
> > > > > James
> > > > >
> > > > > On 2026/04/16 13:31:10 Gianluca Sartori wrote:
> > > > > > Hi folks,
> > > > > >
> > > > > > do you have evidence that the where query aliases are working for
> > > > > sorting?
> > > > > > It does not seem to work in my code.
> > > > > >
> > > > > > The only difference I see is that I sort multiple columns with
> > > something
> > > > > > like:
> > > > > >
> > > > > >     def query = buildQuery(filterParams)
> > > > > >     return query.list(sort: ['o1.firstName': 'desc'])
> > > > > >
> > > > > >
> > > > > >
> > > > > > >>>
> > > > > > 7.4.6. Query Aliases and Sorting
> > > > > >
> > > > > > If you define a query for an association an alias is
> automatically
> > > > > > generated for the query. For example the following query:
> > > > > >
> > > > > > def query = Pet.where {
> > > > > >     owner.firstName == "Fred"
> > > > > > }
> > > > > >
> > > > > > Will generate an alias for the owner association such as
> > > owner_alias_0.
> > > > > > These generated aliases are fine for most cases, but are not
> useful
> > > if
> > > > > you
> > > > > > want to later sort or use a projection on the results. For
> example
> > > the
> > > > > > following query will fail:
> > > > > >
> > > > > > // fails because a dynamic alias is used
> > > > > > Pet.where {
> > > > > >     owner.firstName == "Fred"
> > > > > > }.list(sort:"owner.lastName")
> > > > > >
> > > > > > If you plan to sort the results then an explicit alias should be
> > > used and
> > > > > > these can be defined by simply declaring a variable in the where
> > > query:
> > > > > >
> > > > > > def query = Pet.where {
> > > > > >     def o1 = owner
> > > > > >     o1.firstName == "Fred"
> > > > > > }.list(sort:'o1.lastName')
> > > > > >
> > > > > > Define an alias called o1
> > > > > > Use the alias in the query itself
> > > > > > Use the alias to sort the results
> > > > > >
> > > > > > By assigning the name of an association to a local variable it
> will
> > > > > > automatically become an alias usable within the query itself and
> > > also for
> > > > > > the purposes of sorting or projecting the results.
> > > > > >
> > > > > >
> > > > > >
> > > > > > Gianluca Sartori
> > > > > > --
> > > > > > https://dueuno.com
> > > > > >
> > > > >
> > > >
> > >
> >
>

Reply via email to