Re: GroupBy.map issues when column values are null

871 views
Skip to first unread message

Timo Westkämper

unread,
Jul 11, 2012, 2:59:42 AM7/11/12
to Querydsl on behalf of suchi
Hi.

Can you give me a syntax example of your query?

Br,
Timo

On Wed, Jul 11, 2012 at 8:11 AM, Querydsl on behalf of suchi <quer...@googlegroups.com> wrote:
Hi,

I am using querydsl to get a bunch of records from the database and project it into a dto using the GroupBy.map for one of my columns. I get an InvocationTargetException when the map has any value which is null. I have verified that none of the keys (id columns) are null.The same expression seems to be working fine when I use lists instead of map.

This seems to be occurring in the ConstructorExpression.class. Is this a bug with querydsl and if so will there be a fix for this in the near future.

Also is there support available in querydsl for multiple level hierarchical join queries and being able to project them onto DTOs.

Cheers,
Suchi



--
Timo Westkämper
Mysema Oy
+358 (0)40 591 2172
www.mysema.com



suchi

unread,
Jul 11, 2012, 5:57:34 AM7/11/12
to quer...@googlegroups.com
Hi Timo,

In my scenario a user can have multiple roles and each of these roles can have multiple security groups.

The SQL query is as follows:-

select u1.id,u1.name,r1.id,r1.name,s1.name from users u1
Join roles r1 on u1.role = r1.id
Join security_groups s1 on r1.secgroup = s1.id

I am trying to use the query dsl to project the above query into a dto structure as below

UserDto

Long id;
String name;
List<Long> roleIds;
List<String> roleNames;
List<Long> secIds;

As an example if the user had a role and the role had 2 security groups then I need to have the 1 role coming back in my dto structure. However when I tried to use the groupby.list by specifying the user.Id as the group by expression, the transform method seemed to be returning 2 items for roleIds. To overcome this I used the groupby.map which seems to throw an exception when there are null values in the columns , for instance role names.

Is there support within querydsl to support the kind of scenario I have described above, to flatten a 2 level hierarchy into the one dto?

Please feel free to let me know if you need any more details from my end?

Cheers,
Suchi

Timo Westkämper

unread,
Jul 11, 2012, 3:43:55 PM7/11/12
to quer...@googlegroups.com
Hi Suchi.


keskiviikko, 11. heinäkuuta 2012 12.57.34 UTC+3 suchi kirjoitti:
Hi Timo,

In my scenario a user can have multiple roles and each of these roles can have multiple security groups.

The SQL query is as follows:-

select u1.id,u1.name,r1.id,r1.name,s1.name from users u1
Join roles r1 on u1.role = r1.id
Join security_groups s1 on r1.secgroup = s1.id

I am trying to use the query dsl to project the above query into a dto structure as below

UserDto

Long id;
String name;
List<Long> roleIds;
List<String> roleNames;
List<Long> secIds;


If you used Sets this would be much simpler. At the moment the grouping doesn't support multi level aggregation too well.
 

As an example if the user had a role and the role had 2 security groups then I need to have the 1 role coming back in my dto structure. However when I tried to use the groupby.list by specifying the user.Id as the group by expression, the transform method seemed to be returning 2 items for roleIds. To overcome this I used the groupby.map which seems to throw an exception when there are null values in the columns , for instance role names.

Can you give me a stacktrace for this?
 

Is there support within querydsl to support the kind of scenario I have described above, to flatten a 2 level hierarchy into the one dto?

I modeled your case via Collections https://github.com/mysema/querydsl/blob/master/querydsl-collections/src/test/java/com/mysema/query/collections/GroupBy2Test.java

If you used Sets you could support this directly.

If you have some ideas how this could be supported more elegantly on the syntax level, please share them!

Br,
Timo

 

suchi

unread,
Jul 11, 2012, 9:44:32 PM7/11/12
to quer...@googlegroups.com
Hi Timo,

Thanks for your prompt response. I did indeed toy with the idea of using sets initially but then it won't work well for this scenario.

If user u1 has 2 roles r1 and r2 and r1.id =1 ;r2.id=2 but r1.name="Test",r2.name="Test"

then if I use Set I will get back only 1 item for the name although they belong to different role records.

Is it possible to address this scenario?

Is it possible to request a feature which can do a grouping at a column expression level as opposed to one grouping at the top query level.

Cheers,
Suchi

suchi

unread,
Jul 12, 2012, 1:34:24 AM7/12/12
to quer...@googlegroups.com
Hi Timo,

To circumvent the above problem with sets I tried to use maps. The expression used is as follows:-

Map<Long, UserDto> userDtos = MiniApi.from(user, Lists.newArrayList(u1, u2))
                .innerJoin(user.roles, role)
                .innerJoin(role.groups, group)
                .transform(GroupBy.groupBy(user.id)
                    .as(new QGroupBy2Test_UserDto(
                            user.id,
                            user.name,
                            GroupBy.map(role.id,role.name),
                            GroupBy.map(sec.id,sec.name))));

This works fine as long as role.name and sec.name are not null.

If any of the values in the database for these fields is null, then the following exception is thrown:-

com.mysema.query.types.ExpressionException
    at com.mysema.query.types.ConstructorExpression.newInstance(ConstructorExpression.java:160)
    at com.mysema.query.types.FactoryExpressionUtils.compress(FactoryExpressionUtils.java:129)
    at com.mysema.query.types.FactoryExpressionUtils.access$100(FactoryExpressionUtils.java:27)
    at com.mysema.query.types.FactoryExpressionUtils$FactoryExpressionAdapter.newInstance(FactoryExpressionUtils.java:50)
    at com.mysema.query.jpa.hibernate.FactoryExpressionTransformer.transformTuple(FactoryExpressionTransformer.java:46)
    at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:95)
    at org.hibernate.loader.hql.QueryLoader.getResultList(QueryLoader.java:438)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2263)
    at org.hibernate.loader.Loader.list(Loader.java:2258)
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470)
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355)
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1215)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
    at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)
    at com.mysema.query.jpa.impl.AbstractJPAQuery.getResultList(AbstractJPAQuery.java:222)
    at com.mysema.query.jpa.impl.AbstractJPAQuery.list(AbstractJPAQuery.java:263)
    at com.mysema.query.jpa.impl.AbstractJPAQuery.iterate(AbstractJPAQuery.java:251)
    at com.mysema.query.group.GroupBy.transform(GroupBy.java:96)
    at com.mysema.query.group.GroupBy.transform(GroupBy.java:34)
    at com.mysema.query.support.ProjectableQuery.transform(ProjectableQuery.java:155)
    at nz.govt.justice.eom.pd.domain.repository.AbstractRepository.performQuery(AbstractRepository.java:210)
    at nz.govt.justice.eom.pd.domain.repository.AbstractRepository.genericList(AbstractRepository.java:182)
    at nz.govt.justice.eom.pd.domain.repository.HearingRepositoryImpl.listIncompleteEvents(HearingRepositoryImpl.java:40)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy73.listIncompleteEvents(Unknown Source)
    at nz.govt.justice.eom.pd.domain.repository.HearingRepositoryImplTest.testMultipleDefendantsNullCri(HearingRepositoryImplTest.java:150)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at com.mysema.query.types.ConstructorExpression.newInstance(ConstructorExpression.java:148)
    ... 70 more
Caused by: java.lang.IllegalArgumentException: second should not be null
    at com.mysema.commons.lang.Assert.assertThat(Assert.java:149)
    at com.mysema.commons.lang.Assert.notNull(Assert.java:60)
    at com.mysema.commons.lang.Pair.<init>(Pair.java:21)
    ... 75 more


Is it possible to get a fix sorted out for this asap so I can address the scenario I have outlined.

Cheers,
Suchi


suchi

unread,
Jul 12, 2012, 4:19:46 AM7/12/12
to quer...@googlegroups.com
The version of querydsl we are using is 2.7.0

Timo Westkämper

unread,
Jul 12, 2012, 4:06:07 PM7/12/12
to quer...@googlegroups.com
Hi.

Fixed in this commit https://github.com/mysema/querydsl/commit/9990520d8fbb478ed3a02026db10ae9dfe1fe54f

I will make a new release next week.

Br,
Timo

suchi

unread,
Jul 12, 2012, 5:26:41 PM7/12/12
to quer...@googlegroups.com
Thank you so much Timo. This is going to save us so much time and effort. I will pick up the changes once they have been released and let you know how it goes.

Cheers,
Suchi

suchi

unread,
Jul 17, 2012, 6:25:50 PM7/17/12
to quer...@googlegroups.com
Hi Timo,

Could you please let me know when this will be released?

Cheers,
Suchi

Timo Westkämper

unread,
Jul 18, 2012, 1:21:14 AM7/18/12
to Querydsl on behalf of suchi
Hi

The fix is in 2.7.1.

Timo
Reply all
Reply to author
Forward
0 new messages