Skip to content
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

Reusing of constants in JPQL generation causes issues with hibernate query caching #1429

Closed
strguntbr opened this issue Jul 7, 2015 · 4 comments · Fixed by #2883
Closed
Assignees
Milestone

Comments

@strguntbr
Copy link

I know it's actually an hibernate issue (I also created an issue for hibernate https://hibernate.atlassian.net/browse/HHH-9900) but maybe there is some workaround to avoid the problem I'm not aware of.

QueryDSL reuses constants when generating JPQL in com.mysema.query.jpa.JPQLSerializer.visitConstant(Object constant) thus the following JPAQuery:

new JPAQuery(entityManager).from(QCacheTes.cacheTest).where(QCacheTest.cacheTest.boola.eq(true).and(QCacheTest.cacheTest.boolb.eq(false)).and(QCacheTest.cacheTest.boolc.eq(true)))

results in the following JPQL:

select cacheTest from at.bluesource.CacheTest cacheTest WHERE cacheTest.boola = ?1 AND cacheTest.boolb = ?2 AND cacheTest.boolc = ?1

using the paramters:

{ 1=true, 2=false }

which is problematic when using hibernate query caching as described in the hibernate issue.

Is there any workaround I'm not aware of to avoid those problems? I thought about using Params instead of the raw values (which become constants in the JPAQuery) to avoid the reusing of constants but on the other hand it's not practical because I can't make sure that everybody always uses Params in out project. Maybe there's a way to configure QueryDSL to not reuse constants (after having a look at the code of QueryDSL I'm pretty sure there is no such way - at least in 3.6.4 which is the version we are currently using)? Or maybe there is a way to somehow magically 'convert' all constants to params just before generation of the JPQL query?

@Shredder121
Copy link
Member

Hi.
This is related to #1413, you can use template expressions so that the underlying literal gets serialized into the query instead of being parameterized.

@strguntbr
Copy link
Author

Thanks for the suggestion, but I decided to try another aproach (because I'm, pretty sure that I would forget to use template expressions everywhere and I'm not sure if the template expression approach works with date/time objects)

I just implemented a workaround that treats constants as param expressions and seems to work (at least our tests are still passing and I have not yet found a problem. Maybe the better way would be to treat them like literals? But I think this would not work/create issues with date/time objects...

We are now just using our CustomJPAQuery instead of the JPAQuery globally. I know this workaround is not nice (at least the removed reflection part to get the inCaseOperation flag from the super class is pretty ugly)

public class CustomJPAQuery extends JPAQuery {

    public CustomJPAQuery(EntityManager entityManager) {
        super(entityManager);
    }

    @Override
    protected JPQLSerializer createSerializer() {
        return new CustomJPQLSerializer(getTemplates(), entityManager, queryMixin);
    }
}

public class CustomJPQLSerializer extends JPQLSerializer {
    private static final String         CONSTANT_PREFIX                 = "CONST_";
    private int                         constCount                      = 0;
    private final QueryMixin<JPAQuery>  queryMixin;
    private final JPQLTemplates         templates;

    public CustomJPQLSerializer(JPQLTemplates templates, EntityManager em, QueryMixin<JPAQuery> queryMixin) {
        super(templates, em);
        this.templates = templates;
        this.queryMixin = queryMixin;
    }

    protected boolean isInCaseOperation() {
        // Removed ugly reflection code to check if we are in a case operation ;) (unfortunatley the field inCaseOperation is private in the super class)
        return false;
    }

    @Override
    public void visitConstant(Object constant) {
        if (templates.isCaseWithLiterals() && isInCaseOperation()) {
            // Call visitConstant of super class as the constant will be serialzed as a literal
            // (necessary that case expressions work with hibernate)
            super.visitConstant(constant);
        } else {
            boolean wrap = templates.wrapConstant(constant);
            if (wrap) {
                append("(");
            }
            ParamExpression<Object> param = new Param<Object>(Object.class, CONSTANT_PREFIX + (constCount++));
            queryMixin.set(param, constant);
            visit(param, null);
            if (wrap) {
                append(")");
            }
        }
    }
}

@timowest
Copy link
Member

Maybe we should consider dropping the usage of unique keys, this way we get a more consistent JPQL query string output and it will fix also #1413.

l30thelion pushed a commit to l30thelion/querydsl that referenced this issue Aug 25, 2016
Reusing of constants in JPQL generation causes issues with hibernate
query caching
@stale
Copy link

stale bot commented Jun 3, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jun 3, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 3, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 4, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 7, 2021
@jwgmeligmeyling jwgmeligmeyling self-assigned this Jun 8, 2021
@jwgmeligmeyling jwgmeligmeyling added this to the 5.0 milestone Jun 8, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 8, 2021
jwgmeligmeyling added a commit that referenced this issue Jun 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants