diff --git a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/transformer/correlation/AbstractCorrelatedBatchTupleListTransformer.java b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/transformer/correlation/AbstractCorrelatedBatchTupleListTransformer.java index 8f696ae2aa..9ec8248fb8 100644 --- a/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/transformer/correlation/AbstractCorrelatedBatchTupleListTransformer.java +++ b/entity-view/impl/src/main/java/com/blazebit/persistence/view/impl/objectbuilder/transformer/correlation/AbstractCorrelatedBatchTupleListTransformer.java @@ -203,6 +203,7 @@ public List transform(List tuples) { while (tupleListIter.hasNext()) { Object[] tuple = tupleListIter.next(); Object correlationValue = tuple[startIndex]; + TuplePromise tupleIndexValue = correlationValues.get(correlationValue); if (tupleIndexValue == null) { @@ -210,20 +211,23 @@ public List transform(List tuples) { tupleIndexValue.add(tuple); correlationValues.put(correlationValue, tupleIndexValue); - if (correlationBasisEntity != null) { - correlationParams.add(em.getReference(correlationBasisEntity, tuple[startIndex])); - } else { - correlationParams.add(tuple[startIndex]); - } - - if (batchSize == correlationParams.realSize()) { - Object defaultKey; + // Can't correlate null + if (correlationValue != null) { if (correlationBasisEntity != null) { - defaultKey = jpaProvider.getIdentifier(correlationParams.get(0)); + correlationParams.add(em.getReference(correlationBasisEntity, correlationValue)); } else { - defaultKey = correlationParams.get(0); + correlationParams.add(correlationValue); + } + + if (batchSize == correlationParams.realSize()) { + Object defaultKey; + if (correlationBasisEntity != null) { + defaultKey = jpaProvider.getIdentifier(correlationParams.get(0)); + } else { + defaultKey = correlationParams.get(0); + } + batchLoad(correlationValues, correlationParams, null, defaultKey, viewRootJpqlMacro, BatchCorrelationMode.VALUES); } - batchLoad(correlationValues, correlationParams, null, defaultKey, viewRootJpqlMacro, BatchCorrelationMode.VALUES); } } else { tupleIndexValue.add(tuple); diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/SubviewFetchTest.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/SubviewFetchTest.java new file mode 100644 index 0000000000..257c210d99 --- /dev/null +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/SubviewFetchTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 - 2019 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.view.testsuite.fetch.subview; + +import com.blazebit.persistence.CriteriaBuilder; +import com.blazebit.persistence.testsuite.base.jpa.category.NoDatanucleus; +import com.blazebit.persistence.testsuite.base.jpa.category.NoEclipselink; +import com.blazebit.persistence.testsuite.base.jpa.category.NoOpenJPA; +import com.blazebit.persistence.testsuite.entity.Document; +import com.blazebit.persistence.testsuite.entity.Person; +import com.blazebit.persistence.testsuite.tx.TxVoidWork; +import com.blazebit.persistence.view.EntityViewManager; +import com.blazebit.persistence.view.EntityViewSetting; +import com.blazebit.persistence.view.EntityViews; +import com.blazebit.persistence.view.spi.EntityViewConfiguration; +import com.blazebit.persistence.view.testsuite.AbstractEntityViewTest; +import com.blazebit.persistence.view.testsuite.fetch.subview.model.DocumentSelectSubviewTestView; +import com.blazebit.persistence.view.testsuite.fetch.subview.model.PersonSelectSubview; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import javax.persistence.EntityManager; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +public class SubviewFetchTest extends AbstractEntityViewTest { + + protected Document doc1; + + @Override + public void setUpOnce() { + cleanDatabase(); + transactional(new TxVoidWork() { + @Override + public void work(EntityManager em) { + doc1 = new Document("doc1"); + + Person o1 = new Person("pers1"); + + doc1.setOwner(o1); + + doc1.getStrings().add("s1"); + doc1.getStrings().add("s2"); + + em.persist(o1); + + em.persist(doc1); + + o1.setPartnerDocument(doc1); + } + }); + } + + @Before + public void setUp() { + doc1 = cbf.create(em, Document.class).where("name").eq("doc1").fetch("partners").getResultList().get(0); + } + + @Test + // NOTE: Eclipselink and Datanucleus don't support the single valued id access optimization which causes a cyclic join dependency + @Category({ NoDatanucleus.class, NoOpenJPA.class, NoEclipselink.class }) + public void testSubqueryFetch() { + EntityViewConfiguration cfg = EntityViews.createDefaultConfiguration(); + cfg.addEntityView(DocumentSelectSubviewTestView.class); + cfg.addEntityView(PersonSelectSubview.class); + EntityViewManager evm = cfg.createEntityViewManager(cbf); + + CriteriaBuilder criteria = cbf.create(em, Document.class, "d").orderByAsc("id"); + EntityViewSetting> setting = EntityViewSetting.create(DocumentSelectSubviewTestView.class); + CriteriaBuilder cb = evm.applySetting(setting, criteria); + List results = cb.getResultList(); + + assertEquals(1, results.size()); + } +} diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/DocumentSelectSubviewTestView.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/DocumentSelectSubviewTestView.java new file mode 100644 index 0000000000..b34fa0d0cf --- /dev/null +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/DocumentSelectSubviewTestView.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 - 2019 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.view.testsuite.fetch.subview.model; + +import com.blazebit.persistence.testsuite.entity.Document; +import com.blazebit.persistence.view.EntityView; +import com.blazebit.persistence.view.IdMapping; + +/** + * + * @author Christian Beikov + * @since 1.4.0 + */ +@EntityView(Document.class) +public interface DocumentSelectSubviewTestView { + + @IdMapping + public Long getId(); + + public PersonSelectSubview getResponsiblePerson(); + +} diff --git a/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/PersonSelectSubview.java b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/PersonSelectSubview.java new file mode 100644 index 0000000000..c0a34d3dc1 --- /dev/null +++ b/entity-view/testsuite/src/test/java/com/blazebit/persistence/view/testsuite/fetch/subview/model/PersonSelectSubview.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 - 2019 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.view.testsuite.fetch.subview.model; + +import com.blazebit.persistence.testsuite.entity.Document; +import com.blazebit.persistence.testsuite.entity.Person; +import com.blazebit.persistence.view.EntityView; +import com.blazebit.persistence.view.FetchStrategy; +import com.blazebit.persistence.view.IdMapping; +import com.blazebit.persistence.view.Mapping; + +import java.util.Set; + +/** + * + * @author Christian Beikov + * @since 1.4.0 + */ +@EntityView(Person.class) +public interface PersonSelectSubview { + + @IdMapping + public Long getId(); + + @Mapping(fetch = FetchStrategy.SELECT) + public Set getOwnedDocuments(); + +}