diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/Advertisement.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/Advertisement.java new file mode 100644 index 0000000000..b1bde85730 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/Advertisement.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.manytomany; + +import org.hibernate.annotations.Where; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.OrderBy; +import java.util.Set; + +/** + * @author Chris Cranford + */ +@Entity +public class Advertisement { + @Id + @GeneratedValue + private Integer id; + + @Where(clause = "deleted <> 'true'") + @ManyToMany(fetch = FetchType.EAGER, mappedBy = "advertisements") + @OrderBy("id asc") + private Set attachments; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Set getAttachments() { + return attachments; + } + + public void setAttachments(Set attachments) { + this.attachments = attachments; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/Attachment.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/Attachment.java new file mode 100644 index 0000000000..cc5ec0dbae --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/Attachment.java @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.manytomany; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import java.util.Set; + +/** + * @author Chris Cranford + */ +@Entity +public class Attachment { + @Id + @GeneratedValue + private Integer id; + + @ManyToMany + private Set advertisements; + + private String fileName; + + private String deleted = "false"; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Set getAdvertisements() { + return advertisements; + } + + public void setAdvertisements(Set advertisements) { + this.advertisements = advertisements; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getDeleted() { + return deleted; + } + + public void setDeleted(String deleted) { + this.deleted = deleted; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/ManyToManyWhereTest.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/ManyToManyWhereTest.java new file mode 100644 index 0000000000..fa53eb4280 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/ManyToManyWhereTest.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.manytomany; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * Verifies that @ManyToMany relationships with a @Where clause properly + * loads the collection for issue HHH-9084. + * + * @author Chris Cranford + */ +@TestForIssue( jiraKey = "HHH-9084" ) +public class ManyToManyWhereTest extends BaseCoreFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Advertisement.class, + Attachment.class, + PageAdvertisement.class, + SubjectAdvertisement.class + }; + } + + @Test + public void testManyToManyWithWhereConditional() { + Session session = openSession(); + Transaction transaction = session.beginTransaction(); + // create advertisements + Advertisement advertisement1 = new Advertisement(); + Advertisement advertisement2 = new Advertisement(); + session.saveOrUpdate( advertisement1 ); + session.saveOrUpdate( advertisement2 ); + // create attachment relationships to advertisements + Attachment a1 = new Attachment(); + a1.setFileName( "memo.txt" ); + a1.setAdvertisements( new LinkedHashSet<>( Arrays.asList( advertisement1, advertisement2 ) ) ); + Attachment a2 = new Attachment(); + a2.setFileName( "mickeymouse.jpg" ); + a2.setDeleted( "true" ); + a2.setAdvertisements( new LinkedHashSet<>( Arrays.asList( advertisement1, advertisement2 ) ) ); + advertisement1.setAttachments( new HashSet<>( Arrays.asList( a1, a2 ) ) ); + advertisement2.setAttachments( new HashSet<>( Arrays.asList( a1, a2 ) ) ); + session.saveOrUpdate( a1 ); + session.saveOrUpdate( a2 ); + transaction.commit(); + session.close(); + + // create page advertisement relationships with advertisements + session = openSession(); + transaction = session.beginTransaction(); + List advertisements = (List) session.createQuery( "FROM Advertisement" ).list(); + assertEquals( advertisements.size(), 2 ); + for ( Advertisement advertisement : advertisements ) { + PageAdvertisement pageAd = new PageAdvertisement(); + pageAd.setAdvertisement( advertisement ); + session.persist( pageAd ); + } + transaction.commit(); + session.close(); + + // query relationships and verify @Where condition fragment applies correctly. + session = openSession(); + transaction = session.beginTransaction(); + List ads = (List) session.createQuery( "FROM PageAdvertisement" ).list(); + assertEquals( ads.size(), 2 ); + for ( PageAdvertisement ad : ads ) { + // there is only 1 not deleted attachment + assertEquals( ad.getAdvertisement().getAttachments().size(), 1 ); + for( Attachment attachment : ad.getAdvertisement().getAttachments() ) { + // each attachment linked with two advertisements + assertEquals( attachment.getAdvertisements().size(), 2 ); + } + } + transaction.commit(); + session.close(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/PageAdvertisement.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/PageAdvertisement.java new file mode 100644 index 0000000000..ecbf4fea83 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/PageAdvertisement.java @@ -0,0 +1,29 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.manytomany; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author Chris Cranford + */ +@Entity +public class PageAdvertisement extends SubjectAdvertisement { + @Id + @GeneratedValue + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/manytomany/SubjectAdvertisement.java b/hibernate-core/src/test/java/org/hibernate/test/manytomany/SubjectAdvertisement.java new file mode 100644 index 0000000000..feaf9d45bc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/manytomany/SubjectAdvertisement.java @@ -0,0 +1,27 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.manytomany; + +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToOne; + +/** + * @author Chris Cranford + */ +@MappedSuperclass +public class SubjectAdvertisement { + @OneToOne + private Advertisement advertisement; + + public Advertisement getAdvertisement() { + return advertisement; + } + + public void setAdvertisement(Advertisement advertisement) { + this.advertisement = advertisement; + } +}