-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DetachedCriteria cause QueryException when using property of alias in projection of detachedCriteria #1616
Comments
Since we need to have this kind of functionality I'm trying to work out a workaround. I stitched together this ugly piece of code, which I do not want to put into production, actually, since it relies on internal state of DetachedCriteria and uses private methods. Furthermore I do not really understand the implications of changing the specific internal state. I just want to leave this here for you to see what might go wrong here.
Can be used like this to make the query work
This does of course not qualify as a workaround! |
Any news on this one? I'm asking since for us this is a blocker to migrate to Grails 5/GORM 7, since we have 100+ queries using GORM DetachedCriteria like this. The workaround above is not feasible from my perspective, since it relies on modifying internal state which is clearly not understood by us. Thank you! |
We have the same problem. Did you find any other solution? |
also the same issue after upgrading to Grails 5 |
I think I experience the same: class Person {
Address address
}
class Address {
Street street
}
...
def criteria = Person.where {
address('_a') {
street('_c')
}
projections {
property('_c.id')
}
}
criteria.list() // works fine
Street.where {
id in criteria
}.list() // fails with QueryException Ad-hoc fix for existing setup: @CompileStatic
class CustomHibernateCriterionAdapter {
private static final Method handleAssociationWithAlias;
private static final Method handleAssociation;
private static final Method applySubCriteriaToJunction;
private static final Field associationStack;
static {
handleAssociation = MethodUtils.getMatchingMethod(HibernateQuery, 'handleAssociationQuery', Association, List)
handleAssociationWithAlias = MethodUtils.getMatchingMethod(HibernateQuery, 'handleAssociationQuery', Association, List, String)
associationStack = FieldUtils.getAllFields(AbstractHibernateQuery).find { it.name == 'associationStack' }
applySubCriteriaToJunction = MethodUtils.getMatchingMethod(HibernateCriterionAdapter, 'applySubCriteriaToJunction', PersistentEntity, AbstractHibernateQuery, List, Junction, String)
handleAssociationWithAlias.setAccessible(true)
handleAssociation.setAccessible(true)
associationStack.setAccessible(true)
applySubCriteriaToJunction.setAccessible(true)
}
/**
* Fixes https://github.com/grails/grails-data-mapping/issues/1267
* Fixes https://github.com/grails/grails-data-mapping/issues/1616
*/
static void addCustomAssociationQueryCriterionAdapters() {
def map = (Map) FieldUtils.readStaticField(AbstractHibernateCriterionAdapter, 'criterionAdaptors', true)
map.put(DetachedAssociationCriteria.class, new AbstractHibernateCriterionAdapter.CriterionAdaptor() {
public Criterion toHibernateCriterion(AbstractHibernateQuery hibernateQuery, Query.Criterion criterion, String alias) {
DetachedAssociationCriteria<?> existing = (DetachedAssociationCriteria<?>) criterion;
Method queryMethod;
Object[] args;
if (existing.alias != null) {
queryMethod = handleAssociationWithAlias
args = new Object[] { existing.getAssociation(), existing.getCriteria(), existing.alias }
} else {
queryMethod = handleAssociation
args = new Object[] { existing.getAssociation(), existing.getCriteria() }
}
alias = (String) queryMethod.invoke(hibernateQuery, args)
def association = existing.getAssociation();
def associationStack = (List<Association>) associationStack.get(hibernateQuery)
associationStack.add(association);
try {
def conjunction = Restrictions.conjunction();
applySubCriteriaToJunction.invoke(HibernateQuery.HIBERNATE_CRITERION_ADAPTER,
association.getAssociatedEntity(), hibernateQuery, existing.getCriteria(), conjunction, alias)
return conjunction;
} finally {
associationStack.removeLast();
}
}
});
}
} And in Boostrap: class BootStrap {
def init = { servletContext ->
HibernateQuery.HIBERNATE_CRITERION_ADAPTER // call to initialize adapter itself
CustomHibernateCriterionAdapter.addCustomAssociationQueryCriterionAdapters()
}
def destroy = {
}
} Tested the above with Grails 5, JDK 17, GORM (7.3.4, 8.1 (both)) @puneetbehl Can you please check the above, we have much more very complex DetachedCriteria in use and it works for us. Sorry do not have much time to start a proper PR with a fix and test coverage. Thanks. |
Steps to Reproduce
grails create-app detachedCriteria
cd detachedCriteria
./grailsw create-domain-class Author
./grailsw create-domain-class Book
Try to use the domain classes in a controller or service as follows while using a grails.gorm.DetachedCriteria for a sub-select in the query. The query below is of course inefficient, but demonstrates the issue.
Expected Behaviour
The above query should execute just fine.
Actual Behaviour
Stacktrace:
Environment Information
Demo
https://github.com/scaiandre/grails-gorm-issue-detachedCriteria
./gradlew bootRun
curl http://localhost:8080/detachedCriteria
Related issue Unknown entity: null
When instead using the alias property in a filter clause, like "eq", the exception is different.
Stacktrace
Just using createAlias without referring to it, works
This does not raise an exception
The text was updated successfully, but these errors were encountered: