DATAJPA-763 - Building up joins now considers already registered fetches, too.
QueryUtils.toExpressionRecursively(…) now also checks the provided root for already existing fetches to avoid creating superfluous join. Original pull request: #151.
This commit is contained in:
committed by
Oliver Gierke
parent
8de3100299
commit
3aa0912e15
@@ -40,6 +40,7 @@ import javax.persistence.Parameter;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Fetch;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
@@ -469,7 +470,7 @@ public abstract class QueryUtils {
|
||||
propertyPathModel = from.get(segment).getModel();
|
||||
}
|
||||
|
||||
if (requiresJoin(propertyPathModel, model instanceof PluralAttribute)) {
|
||||
if (requiresJoin(propertyPathModel, model instanceof PluralAttribute) && !isAlreadyFetched(from, segment)) {
|
||||
Join<?, ?> join = getOrCreateJoin(from, segment);
|
||||
return (Expression<T>) (property.hasNext() ? toExpressionRecursively(join, property.next()) : join);
|
||||
} else {
|
||||
@@ -544,4 +545,16 @@ public abstract class QueryUtils {
|
||||
|
||||
return from.join(attribute, JoinType.LEFT);
|
||||
}
|
||||
|
||||
|
||||
private static boolean isAlreadyFetched(final From<?, ?> from, final String attribute) {
|
||||
for(final Fetch<?, ?> f : from.getFetches()) {
|
||||
final boolean sameName = f.getAttribute().getName().equals(attribute);
|
||||
|
||||
if(sameName && f.getJoinType().equals(JoinType.LEFT)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import javax.persistence.Persistence;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.spi.PersistenceProvider;
|
||||
import javax.persistence.spi.PersistenceProviderResolver;
|
||||
@@ -39,7 +40,9 @@ import javax.persistence.spi.PersistenceProviderResolverHolder;
|
||||
import org.hibernate.ejb.HibernatePersistence;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.data.jpa.domain.sample.Category;
|
||||
import org.springframework.data.jpa.domain.sample.Order;
|
||||
import org.springframework.data.jpa.domain.sample.Product;
|
||||
import org.springframework.data.jpa.domain.sample.User;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -142,6 +145,21 @@ public class QueryUtilsIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-763
|
||||
*/
|
||||
@Test
|
||||
public void doesNotCreateAJoinForAlreadyFetchedAssociation() {
|
||||
|
||||
final CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<Category> query = builder.createQuery(Category.class);
|
||||
final Root<Category> root = query.from(Category.class);
|
||||
root.fetch("product", JoinType.LEFT);
|
||||
|
||||
QueryUtils.toExpressionRecursively(root, PropertyPath.from("product", Category.class));
|
||||
assertThat(root.getJoins(), is(empty()));
|
||||
}
|
||||
|
||||
protected void assertNoJoinRequestedForOptionalAssociation(Root<Order> root) {
|
||||
assertThat(root.getJoins(), is(empty()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user