blaze-persistence icon indicating copy to clipboard operation
blaze-persistence copied to clipboard

.selectNew().withSubquery() does't seem to work properly

Open cgraefe opened this issue 2 years ago • 4 comments

Description

I'm trying to use the criteria builder "select new" feature together with a subquery. In a simplified example along the lines of:

CriteriaBuilder<CatModel> cb = cbf.create(em, Tuple.class)
    .from(Cat.class, "cat")
    .selectNew(CatModel.class)
        .with("cat.name")
        .withSubquery("offspring")
            .from(Cat.class, "child")
            .select("COUNT(*)")
            .where("child.mother.id").eqExpression("cat.id")
        .end()
        .with("cat.age")
    .end();

Expected behavior

I would expect the method getResultList() to query the database and create a list of CatModel instances, calling the constructor with the result of the subquery among the other arguments.

Actual behavior

An exception is thrown when the query is built:

com.blazebit.persistence.impl.BuilderChainingException: A builder was not ended properly.

	at com.blazebit.persistence.impl.builder.object.SelectObjectBuilderImpl.verifySubqueryBuilderEnded(SelectObjectBuilderImpl.java:110)
	at com.blazebit.persistence.impl.builder.object.SelectObjectBuilderImpl.with(SelectObjectBuilderImpl.java:79)
	at com.blazebit.persistence.impl.builder.object.SelectObjectBuilderImpl.with(SelectObjectBuilderImpl.java:70)
        ...

I suspect that subqueryStartMarker in SelectObjectBuilderImpl should be reset in onBuilderEnded() in a similar way that multipleSubqueryStartMarker is reset.

Steps to reproduce

I have not created a special test case that I could share, yet. But I will do so if it actually helps in this case.

Environment

Version: 1.6.8 JPA-Provider: Hibernate 5.6.14.Final DBMS: Oracle 11g Application Server: Tomcat, Spring Framework

cgraefe avatar Mar 13 '23 11:03 cgraefe

Hi there. Do you understand that the parameter you pass to withSubquery() is the select item alias? Could you try omitting that for the sake of testing? Also, did you try using the withSubqueries() as a workaround yet i.e. .withSubqueries("mysubquery").with("mysubquery")...end()?

We actually have a test for this, which is why I am a bit surprised that you run into this. See https://github.com/Blazebit/blaze-persistence/blob/08793f4ab72cd57762bb6d222ad1fa9421f23e22/core/testsuite/src/test/java/com/blazebit/persistence/testsuite/SelectNewTest.java#L110-L109

Would be cool if you could create a PR with a test case that shows the error, preferably by adding a method like the one I pointed you to.

beikov avatar Mar 13 '23 11:03 beikov

Thanks for the blazingly fast response! I was indeed going to try withSubqueries() next, but I'll be caught up in meetings for the rest of the day. I will get back to you on those points by tomorrow.

cgraefe avatar Mar 13 '23 11:03 cgraefe

Omitting the select alias did not change the behavior, but I can indeed work around the issue for now by using withSubqueries().

The error occurs only if the withSubquery() is followed by another select item. It seems to go unnoticed in cases where the withSubquery() item is the last one in the list.

I added two additional test methods as you suggested and I will create a PR, shortly. I actually don't use Github very often so I hope I'm doing it right.

cgraefe avatar Mar 13 '23 18:03 cgraefe

Great work, thanks for the reproducer. I'll look as soon as I can!

beikov avatar Mar 13 '23 18:03 beikov