diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Address.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Address.java
new file mode 100644
index 0000000000..34bc0d192b
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Address.java
@@ -0,0 +1,45 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2015, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.criteria;
+
+/**
+ * @author Gail Badner
+ */
+public class Address {
+ private int addressId;
+
+ public int getAddressId() {
+ return addressId;
+ }
+
+ private String addressText;
+
+ public String getAddressText() {
+ return addressText;
+ }
+
+ public void setAddressText(String addressText) {
+ this.addressText = addressText;
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.hbm.xml
index 73652724ba..8842bfae5e 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.hbm.xml
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.hbm.xml
@@ -6,10 +6,15 @@
+
+
+
+
+
@@ -18,5 +23,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.java
index e6998e35de..1f63110007 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Order.java
@@ -29,24 +29,45 @@ import java.util.Set;
public class Order {
- private int orderId;
+ private int orderId;
- public int getOrderId() {
+ public int getOrderId() {
return orderId;
}
- private Set orderLines = new HashSet();
+ private Set orderLines = new HashSet();
- public Set getLines() {
+ public Set getLines() {
return Collections.unmodifiableSet(orderLines);
}
- public void addLine(OrderLine orderLine){
- orderLine.setOrder(this);
- this.orderLines.add(orderLine);
- }
-
- public String toString() {
+ public void addLine(OrderLine orderLine){
+ orderLine.setOrder(this);
+ this.orderLines.add(orderLine);
+ }
+
+ private Set orderContacts = new HashSet();
+
+ public Set getContacts() {
+ return Collections.unmodifiableSet(orderContacts);
+ }
+
+ public void addContact(OrderContact orderContact){
+ orderContact.getOrders().add( this );
+ this.orderContacts.add(orderContact);
+ }
+
+ public OrderAddress orderAddress;
+
+ public OrderAddress getOrderAddress() {
+ return orderAddress;
+ }
+
+ public void setOrderAddress(OrderAddress orderAddress) {
+ this.orderAddress = orderAddress;
+ }
+
+ public String toString() {
return "" + getOrderId() + " - " + getLines();
}
}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderAddress.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderAddress.java
new file mode 100644
index 0000000000..fae6e5e477
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderAddress.java
@@ -0,0 +1,60 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2015, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.criteria;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class OrderAddress {
+
+ private int orderAddressId;
+
+ public int getOrderAddressId() {
+ return orderAddressId;
+ }
+
+ private Address deliveryAddress;
+
+ public Address getDeliveryAddress() {
+ return deliveryAddress;
+ }
+
+ public void setDeliveryAddress(Address deliveryAddress) {
+ this.deliveryAddress = deliveryAddress;
+ }
+
+ private Set notifiedAddresses = new HashSet();
+
+ public Set getNotifiedAddresses() {
+ return notifiedAddresses;
+ }
+
+ public void setNotifiedAddresses(Set notifiedAddresses) {
+ this.notifiedAddresses = notifiedAddresses;
+ }
+
+ public String toString() {
+ return "" + orderAddressId + " - " + getDeliveryAddress() + " - " + getNotifiedAddresses();
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderContact.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderContact.java
new file mode 100644
index 0000000000..941e5d9e9f
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/OrderContact.java
@@ -0,0 +1,56 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2011, Red Hat Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors. All third-party contributions are
+ * distributed under license by Red Hat Inc.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301 USA
+ */
+package org.hibernate.test.criteria;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class OrderContact {
+
+ private int contactId = 0;
+ private Set orders = new HashSet();
+
+ private String contact;
+
+
+ public int getContactId() {
+ return contactId;
+ }
+
+ public Set getOrders() {
+ return orders;
+ }
+
+ public String getContact() {
+ return contact;
+ }
+
+ public void setContact(String contact) {
+ this.contact = contact;
+ }
+
+ public String toString() {
+ return "[" + getContactId() + ":" + getContact() + "]";
+ }
+}
\ No newline at end of file
diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/OuterJoinCriteriaTest.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/OuterJoinCriteriaTest.java
index e17e6a150a..8ec996d993 100644
--- a/hibernate-core/src/test/java/org/hibernate/test/criteria/OuterJoinCriteriaTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/OuterJoinCriteriaTest.java
@@ -30,9 +30,13 @@ import java.util.Map;
import org.junit.Test;
import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
import org.hibernate.Session;
+import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinFragment;
+import org.hibernate.sql.JoinType;
+import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@@ -381,6 +385,190 @@ public class OuterJoinCriteriaTest extends BaseCoreFunctionalTestCase {
s.close();
}
+ @Test
+ @TestForIssue( jiraKey = "HHH-9597")
+ public void testMultipleSubCriteriaRestrictionsOnCollections() {
+ Session s = openSession();
+ s.getTransaction().begin();
+
+ Criteria rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria( "order.orderLines", "line", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("line.articleId", "3000"));
+ rootCriteria.createCriteria( "order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("contact.contact", "Contact1"));
+ // result should be order1, because that's the only Order with:
+ // 1) orderLines containing an OrderLine with articleId == "3000"
+ // and 2) orderContacts containing an OrderContact with contact == "Contact1"
+ // Since both restrictions are in subcriteria, both collections should be non-filtered
+ // (i.e. includes all elements in both collections)
+ Order result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 2, result.getContacts().size() );
+ assertEquals( 2, result.getLines().size() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ @Test
+ @TestForIssue( jiraKey = "HHH-9597")
+ public void testMultipleRootCriteriaRestrictionsOnCollections() {
+ Session s = openSession();
+ s.getTransaction().begin();
+
+ Criteria rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createAlias( "order.orderLines", "line", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("line.articleId", "3000"));
+ rootCriteria.createAlias("order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN)
+ .add( Restrictions.eq( "contact.contact", "Contact1" ) );
+ // result should be order1, because that's the only Order with:
+ // 1) orderLines containing an OrderLine with articleId == "3000"
+ // and 2) orderContacts containing an OrderContact with contact == "Contact1"
+ // Since both restrictions are in root criteria, both collections should be filtered
+ // to contain only the elements that satisfy the restrictions.
+ Order result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 1, result.getLines().size() );
+ assertEquals( "3000", result.getLines().iterator().next().getArticleId() );
+ assertEquals( 1, result.getContacts().size() );
+ assertEquals( "Contact1", result.getContacts().iterator().next().getContact() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ @Test
+ @TestForIssue( jiraKey = "HHH-9597")
+ public void testRootAndSubCriteriaRestrictionsOnCollections() {
+ // the result of all Criteria in this test will be order1, because that's the only Order with:
+ // 1) orderLines containing an OrderLine with articleId == "3000"
+ // and 2) orderContacts containing an OrderContact with contact == "Contact1"
+
+ Session s = openSession();
+ s.getTransaction().begin();
+ Criteria rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria("order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN)
+ .add( Restrictions.eq( "contact.contact", "Contact1" ) );
+ rootCriteria.createAlias("order.orderLines", "line", JoinType.LEFT_OUTER_JOIN)
+ .add(Restrictions.eq("line.articleId", "3000"));
+ // Since restriction on orderLines is on root criteria, that collection should be filtered.
+ // Since restriction on orderContacts is on a subcriteria, that collection should be
+ // non-filtered (contain all its elements)
+ Order result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 1, result.getLines().size() );
+ assertEquals( "3000", result.getLines().iterator().next().getArticleId() );
+ assertEquals( 2, result.getContacts().size() );
+ s.getTransaction().commit();
+ s.close();
+
+ // The following should have the same result as the previous, since it has the same
+ // restrictions applied in reverse order.
+
+ s = openSession();
+ s.getTransaction().begin();
+ rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria("order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN)
+ .add(Restrictions.eq("contact.contact", "Contact1"));
+ rootCriteria.createAlias( "order.orderLines", "line", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("line.articleId", "3000"));
+ // Since restriction on orderLines is on root criteria, that collection should be filtered.
+ // Since restriction on orderContacts is on a subcriteria, that collection should be
+ // non-filtered (contain all its elements)
+ result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 1, result.getLines().size() );
+ assertEquals( "3000", result.getLines().iterator().next().getArticleId() );
+ assertEquals( 2, result.getContacts().size() );
+ s.getTransaction().commit();
+ s.close();
+
+ // Even though the following seem redundant, there was a failure due to HHH-9597
+ // that reproduced when filtering Order.orderContacts, but not order.orderLines.
+
+ s = openSession();
+ s.getTransaction().begin();
+ rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createAlias( "order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("contact.contact", "Contact1"));
+ rootCriteria.createCriteria( "order.orderLines", "line", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("line.articleId", "3000"));
+ // Since restriction on orderContacts is on root criteria, that collection should be filtered.
+ // Since restriction on orderLines is on a subcriteria, that collection should be
+ // non-filtered (contain all its elements)
+ result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 2, result.getLines().size() );
+ assertEquals( 1, result.getContacts().size() );
+ assertEquals( "Contact1", result.getContacts().iterator().next().getContact() );
+ s.getTransaction().commit();
+ s.close();
+
+ // The following should have the same result as the previous, since it has the same
+ // restrictions applied in reverse order.
+
+ s = openSession();
+ s.getTransaction().begin();
+ rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria( "order.orderLines", "line", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("line.articleId", "3000"));
+ rootCriteria.createAlias( "order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN )
+ .add(Restrictions.eq("contact.contact", "Contact1"));
+ result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 2, result.getLines().size() );
+ assertEquals( 1, result.getContacts().size() );
+ assertEquals( "Contact1", result.getContacts().iterator().next().getContact() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ @Test
+ @TestForIssue( jiraKey = "HHH-9597")
+ public void testSubCriteriaRestrictionsOnCollectionsNestedInManyToOne() {
+ // the result of all Criteria in this test will be order1, because that's the only Order with:
+ // 1) orderContacts containing an OrderContact with contact == "Contact1"
+ // and 2) orderAddress.notifiedAddresses containing an Address with addressText == "over the rainbow"
+
+ Session s = openSession();
+ s.getTransaction().begin();
+ Criteria rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria("order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN)
+ .add( Restrictions.eq( "contact.contact", "Contact1" ) );
+ rootCriteria.createCriteria( "order.orderAddress", "orderAddress", JoinType.LEFT_OUTER_JOIN )
+ .createCriteria( "orderAddress.notifiedAddresses", "notifiedAddress", JoinType.LEFT_OUTER_JOIN )
+ .add( Restrictions.eq( "notifiedAddress.addressText", "over the rainbow" ) );
+
+ // Since restrictions are on subcriteria, the collections should n on orderLines is on root criteria, that collection should be filtered.
+ // Since restriction on orderContacts is on a subcriteria, that collection should be
+ // non-filtered (contain all its elements)
+ Order result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 2, result.getContacts().size() );
+ assertEquals( 2, result.getOrderAddress().getNotifiedAddresses().size() );
+ s.getTransaction().commit();
+ s.close();
+
+ // The following should have the same result as the previous, since it has the same
+ // restrictions applied in reverse order.
+
+ s = openSession();
+ s.getTransaction().begin();
+ rootCriteria = s.createCriteria(Order.class, "order");
+ rootCriteria.createCriteria( "order.orderAddress", "orderAddress", JoinType.LEFT_OUTER_JOIN )
+ .createCriteria( "orderAddress.notifiedAddresses", "notifiedAddress", JoinType.LEFT_OUTER_JOIN )
+ .add( Restrictions.eq( "notifiedAddress.addressText", "over the rainbow" ) );
+ rootCriteria.createCriteria("order.orderContacts", "contact", JoinType.LEFT_OUTER_JOIN)
+ .add( Restrictions.eq( "contact.contact", "Contact1" ) );
+ // Since restrictions are on subcriteria, the collections should n on orderLines is on root criteria, that collection should be filtered.
+ // Since restriction on orderContacts is on a subcriteria, that collection should be
+ // non-filtered (contain all its elements)
+ result = (Order) rootCriteria.uniqueResult();
+ assertEquals( order1.getOrderId(), result.getOrderId() );
+ assertEquals( 2, result.getContacts().size() );
+ assertEquals( 2, result.getOrderAddress().getNotifiedAddresses().size() );
+ s.getTransaction().commit();
+ s.close();
+ }
+
protected void prepareTest() {
Session s = openSession();
s.getTransaction().begin();
@@ -395,8 +583,30 @@ public class OuterJoinCriteriaTest extends BaseCoreFunctionalTestCase {
order1.addLine( line );
s.persist( order1 );
+ OrderContact contact = new OrderContact();
+ contact.setContact( "Contact1" );
+ order1.addContact( contact );
+ contact = new OrderContact();
+ contact.setContact( "Contact2" );
+ order1.addContact( contact );
+
+ OrderAddress orderAddress = new OrderAddress();
+ Address address = new Address();
+ address.setAddressText( "over the rainbow" );
+ orderAddress.setDeliveryAddress( address );
+ Address otherAddress = new Address();
+ otherAddress.setAddressText( "other place" );
+ orderAddress.getNotifiedAddresses().add( address );
+ orderAddress.getNotifiedAddresses().add( otherAddress );
+ order1.setOrderAddress( orderAddress );
+
+ s.persist( order1 );
+
// Order with no lines
order2 = new Order();
+ contact = new OrderContact();
+ contact.setContact( "Contact1" );
+ order2.addContact( contact );
s.persist( order2 );
// Order with non-matching line
@@ -414,6 +624,13 @@ public class OuterJoinCriteriaTest extends BaseCoreFunctionalTestCase {
Session s = openSession();
s.getTransaction().begin();
+ List orders = s.createQuery( "from Order" ).list();
+
+ for( Object order : orders ) {
+ s.delete( order );
+ }
+ s.createQuery( "delete from OrderContact" ).executeUpdate();
+
s.createQuery( "delete from OrderLine" ).executeUpdate();
s.createQuery( "delete from Order" ).executeUpdate();