diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/NativeSQLSerializer.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/NativeSQLSerializer.java index 756802c62..4231b0859 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/NativeSQLSerializer.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/NativeSQLSerializer.java @@ -13,13 +13,17 @@ */ package com.mysema.query.jpa; -import javax.persistence.Table; import javax.persistence.Column; -import java.util.*; +import javax.persistence.Table; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.mysema.query.JoinExpression; import com.mysema.query.QueryMetadata; import com.mysema.query.sql.*; @@ -34,7 +38,7 @@ import com.mysema.query.types.*; */ public final class NativeSQLSerializer extends SQLSerializer { - private final Map, String> aliases = Maps.newHashMap(); + private final ListMultimap, String> aliases = ArrayListMultimap.create(); private final boolean wrapEntityProjections; @@ -78,7 +82,7 @@ public final class NativeSQLSerializer extends SQLSerializer { return expr instanceof Operation && ((Operation)expr).getOperator() == Ops.ALIAS; } - public Map, String> getAliases() { + public ListMultimap, String> getAliases() { return aliases; } diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/hibernate/sql/AbstractHibernateSQLQuery.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/hibernate/sql/AbstractHibernateSQLQuery.java index 847b5cf86..79bfadc83 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/hibernate/sql/AbstractHibernateSQLQuery.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/hibernate/sql/AbstractHibernateSQLQuery.java @@ -15,8 +15,10 @@ package com.mysema.query.jpa.hibernate.sql; import javax.annotation.Nullable; import java.util.List; -import java.util.Map; +import java.util.Set; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Sets; import com.mysema.commons.lang.CloseableIterator; import com.mysema.query.*; import com.mysema.query.NonUniqueResultException; @@ -86,7 +88,8 @@ public abstract class AbstractHibernateSQLQuery, String> aliases = serializer.getAliases(); + ListMultimap, String> aliases = serializer.getAliases(); + Set used = Sets.newHashSet(); // set entity paths List> projection = queryMixin.getMetadata().getProjection(); Expression proj = projection.get(0); @@ -95,13 +98,25 @@ public abstract class AbstractHibernateSQLQuery> exte query = entityManager.createNativeQuery(queryString); } if (!forCount) { - Map, String> aliases = serializer.getAliases(); + ListMultimap, String> aliases = serializer.getAliases(); + Set used = Sets.newHashSet(); if (proj instanceof FactoryExpression) { for (Expression expr : ((FactoryExpression)proj).getArgs()) { if (isEntityExpression(expr)) { queryHandler.addEntity(query, extractEntityExpression(expr).toString(), expr.getType()); } else if (aliases.containsKey(expr)) { - queryHandler.addScalar(query, aliases.get(expr), expr.getType()); + for (String scalar : aliases.get(expr)) { + if (!used.contains(scalar)) { + queryHandler.addScalar(query, scalar, expr.getType()); + used.add(scalar); + break; + } + + } } } } else if (isEntityExpression(proj)) { queryHandler.addEntity(query, extractEntityExpression(proj).toString(), proj.getType()); } else if (aliases.containsKey(proj)) { - queryHandler.addScalar(query, aliases.get(proj), proj.getType()); + for (String scalar : aliases.get(proj)) { + if (!used.contains(scalar)) { + queryHandler.addScalar(query, scalar, proj.getType()); + used.add(scalar); + break; + } + } } } diff --git a/querydsl-jpa/src/test/java/com/mysema/query/AbstractSQLTest.java b/querydsl-jpa/src/test/java/com/mysema/query/AbstractSQLTest.java index e723a4ea6..25d49d7e7 100644 --- a/querydsl-jpa/src/test/java/com/mysema/query/AbstractSQLTest.java +++ b/querydsl-jpa/src/test/java/com/mysema/query/AbstractSQLTest.java @@ -12,10 +12,7 @@ import com.mysema.query.jpa.domain.QCat; import com.mysema.query.jpa.domain.QCompany; import com.mysema.query.jpa.domain.sql.SAnimal; import com.mysema.query.sql.SQLSubQuery; -import com.mysema.query.types.ConstructorExpression; -import com.mysema.query.types.Expression; -import com.mysema.query.types.Projections; -import com.mysema.query.types.SubQueryExpression; +import com.mysema.query.types.*; import com.mysema.query.types.expr.DateExpression; import com.mysema.query.types.expr.Wildcard; import com.mysema.testutil.ExcludeIn; @@ -249,6 +246,12 @@ public abstract class AbstractSQLTest { } } + @Test + public void Projections_DuplicateColumns() { + SAnimal cat = new SAnimal("cat"); + assertEquals(1, query().from(cat).list(new QList(cat.count(), cat.count())).size()); + } + @Test public void Single_Result() { query().from(cat).singleResult(cat.id); @@ -357,4 +360,5 @@ public abstract class AbstractSQLTest { // print(rows); } + } diff --git a/querydsl-root/pom.xml b/querydsl-root/pom.xml index 861226a6b..4d2f0c6b6 100644 --- a/querydsl-root/pom.xml +++ b/querydsl-root/pom.xml @@ -213,6 +213,9 @@ + + com/mysema/query/jpa/NativeSQLSerializer + BACKWARD_COMPATIBLE_USER true true