Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@
import com.querydsl.jpa.FactoryExpressionTransformer;
import com.querydsl.jpa.HQLTemplates;
import com.querydsl.jpa.JPAQueryBase;
import com.querydsl.jpa.JPAQueryMixin;
import com.querydsl.jpa.JPQLTemplates;
import com.querydsl.jpa.ScrollableResultsIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
Expand Down Expand Up @@ -213,7 +216,11 @@ public Stream<T> stream() {
@SuppressWarnings("unchecked")
public List<T> fetch() {
try {
return createQuery().list();
List<T> results = createQuery().list();
if (hasFetchJoin()) {
results = new ArrayList<>(new LinkedHashSet<>(results));
}
return results;
} finally {
reset();
}
Expand All @@ -230,6 +237,9 @@ public QueryResults<T> fetchResults() {
var query = createQuery(modifiers, false);
@SuppressWarnings("unchecked")
List<T> list = query.list();
if (hasFetchJoin()) {
list = new ArrayList<>(new LinkedHashSet<>(list));
}
return new QueryResults<>(list, modifiers, total);
} else {
return QueryResults.emptyResults();
Expand All @@ -239,6 +249,16 @@ public QueryResults<T> fetchResults() {
}
}

/**
* Check if any join in this query has a fetch join flag.
*
* @return true if at least one join uses fetchJoin
*/
private boolean hasFetchJoin() {
return getMetadata().getJoins().stream()
.anyMatch(join -> join.getFlags().contains(JPAQueryMixin.FETCH));
}

protected void logQuery(String queryString) {
if (logger.isLoggable(Level.FINE)) {
var normalizedQuery = queryString.replace('\n', ' ');
Expand Down Expand Up @@ -363,6 +383,17 @@ public T fetchOne() throws NonUniqueResultException {
try {
var modifiers = getMetadata().getModifiers();
var query = createQuery(modifiers, false);
if (hasFetchJoin()) {
List<T> results = query.list();
results = new ArrayList<>(new LinkedHashSet<>(results));
if (results.isEmpty()) {
return null;
} else if (results.size() == 1) {
return results.get(0);
} else {
throw new NonUniqueResultException();
}
}
try {
return (T) query.uniqueResult();
} catch (org.hibernate.NonUniqueResultException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.jpa.JPAQueryBase;
import com.querydsl.jpa.JPAQueryMixin;
import com.querydsl.jpa.JPQLSerializer;
import com.querydsl.jpa.JPQLTemplates;
import com.querydsl.jpa.QueryHandler;
Expand Down Expand Up @@ -179,10 +180,11 @@ protected Query createQuery(@Nullable QueryModifiers modifiers, boolean forCount
*/
private List<?> getResultList(Query query) {
// TODO : use lazy fetch here?
List<?> results;
if (projection != null) {
List<?> results = query.getResultList();
List<Object> rv = new ArrayList<>(results.size());
for (Object o : results) {
List<?> raw = query.getResultList();
List<Object> rv = new ArrayList<>(raw.size());
for (Object o : raw) {
if (o != null) {
if (!o.getClass().isArray()) {
o = new Object[] {o};
Expand All @@ -192,10 +194,29 @@ private List<?> getResultList(Query query) {
rv.add(projection.newInstance(new Object[] {null}));
}
}
return rv;
results = rv;
} else {
return query.getResultList();
results = query.getResultList();
}

// Deduplicate results when fetchJoin is used.
// Since Hibernate 6, automatic deduplication on fetch joins was removed,
// so we handle it at the QueryDSL level for all JPA providers.
if (hasFetchJoin()) {
results = new ArrayList<>(new LinkedHashSet<>(results));
}

return results;
}

/**
* Check if any join in this query has a fetch join flag.
*
* @return true if at least one join uses fetchJoin
*/
private boolean hasFetchJoin() {
return getMetadata().getJoins().stream()
.anyMatch(join -> join.getFlags().contains(JPAQueryMixin.FETCH));
}

/**
Expand Down Expand Up @@ -336,6 +357,19 @@ protected void reset() {}
@Override
public T fetchOne() throws NonUniqueResultException {
try {
if (hasFetchJoin()) {
// When fetchJoin is used, use getResultList with deduplication
// to avoid NonUniqueResultException caused by JOIN duplicates
var query = createQuery(getMetadata().getModifiers(), false);
var results = (List<T>) getResultList(query);
if (results.isEmpty()) {
return null;
} else if (results.size() == 1) {
return results.get(0);
} else {
throw new NonUniqueResultException();
}
}
var query = createQuery(getMetadata().getModifiers(), false);
return (T) getSingleResult(query);
} catch (jakarta.persistence.NoResultException e) {
Expand Down
Loading