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:
Matthias Herrmann
2015-07-20 08:45:07 +02:00
committed by Oliver Gierke
parent 8de3100299
commit 3aa0912e15
2 changed files with 32 additions and 1 deletions

View File

@@ -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;
}
}

View File

@@ -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()));
}