/******************************************************************************* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2013,2014 by Peter Pilgrim, Addiscombe, Surrey, XeNoNiQUe UK * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU GPL v3.0 * which accompanies this distribution, and is available at: * http://www.gnu.org/licenses/gpl-3.0.txt * * Developers: * Peter Pilgrim -- design, development and implementation * -- Blog: http://www.xenonique.co.uk/blog/ * -- Twitter: @peter_pilgrim * * Contributors: * *******************************************************************************/ package je7hb.basic4.jpa.manytomany; import je7hb.Utils; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ArchivePaths; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import javax.annotation.Resource; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.transaction.UserTransaction; import java.util.*; import static org.junit.Assert.*; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import je7hb.Utils; /** * A unit test OneToOneRelationshipTest to verify the operation of OneToOneRelationshipTest * * <p> JPA Notes: Modify both sides of the relationship </p * * <ol> * <li> * If you have a bi-directional ManyToMany relationship, * ensure that you add to both sides of the relationship. * </li> * * <li> If you have a bidirectional ManyToMany relationship, * you must use mappedBy on one side of the relationship, * otherwise it will be assumed to be two difference relationships * and you will get duplicate rows inserted into the join table. * </li> * </ol> * * <p>Here we validate the many to many relationship by breaking it * into two relationships <em>one-to-many</em> and <em>many-to-one</em>. * </p> * * @author Peter Pilgrim */ @RunWith(Arquillian.class) public class ManyToManyRelationshipTest { private List<Product> products; private List<Invoice> invoices; @Deployment public static JavaArchive createDeployment() { JavaArchive jar = ShrinkWrap.create(JavaArchive.class) .addClasses(Product.class) .addClasses(Invoice.class) .addAsResource( "test-persistence.xml", "META-INF/persistence.xml") .addAsManifestResource( EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml")); return jar; } @PersistenceContext EntityManager em; @Resource UserTransaction utx; @Before public void cleanDatabase() throws Exception { utx.begin(); assertNotNull(em); em.joinTransaction(); em.createQuery("delete from "+Product.class.getSimpleName()).executeUpdate(); em.createQuery("delete from "+Invoice.class.getSimpleName()).executeUpdate(); utx.commit(); } @After public void clearEntityManager() { Utils.clearEntityManager(em); } private void createEntities() { products = Arrays.asList( new Product(100,"Forged Nuts"), new Product(101,"Steel Spirals"), new Product(102,"Bolt Fasteners"), new Product(103,"Ridge Drill"), new Product(104,"Mason Hammer") ); invoices = Arrays.asList( new Invoice(1,"Appleton"), new Invoice(2,"Falvestron"), new Invoice(3,"Johnstone"), new Invoice(4,"Pemberton") ); } public static <A,B> void assertEqualsOnCollectionsAnyOrder( Collection<A> source, Collection<B> target ) { assertEquals("collection sizes are different", source.size(), target.size()); for (Object obj:source) { if (!target.contains(obj)) { fail("collections are different target does not contain source object: " + obj); } } } @Test public void shouldPersistProductsAndInvoicesWithoutLinks() throws Exception { // Assign createEntities(); // Act utx.begin(); for ( Product prod: products) { em.persist(prod); } for ( Invoice inv: invoices) { em.persist(inv); } utx.commit(); System.out.printf("products = %s\n", products ); System.out.printf("invoices = %s\n", invoices ); // Asserts for ( Product prod: products) { assertTrue( prod.getId() > 0 ); } // Asserts for ( Invoice inv: invoices) { assertTrue( inv.getId() > 0 ); } } @Test public void shouldPersistOneProductWithManyInvoices() throws Exception { // Assign createEntities(); Product expectedProduct = products.get(1); List<Invoice> expectedInvoices = Arrays.asList(invoices.get(0), invoices.get(2)); expectedProduct.getInvoices().add( invoices.get(0)); expectedProduct.getInvoices().add( invoices.get(2)); invoices.get(0).getProducts().add( expectedProduct); invoices.get(2).getProducts().add( expectedProduct); // Act utx.begin(); for ( Product prod: products) { em.persist(prod); } for ( Invoice inv: invoices) { em.persist(inv); } utx.commit(); System.out.printf("products = %s\n", products ); System.out.printf("invoices = %s\n", invoices ); utx.begin(); System.out.printf("expectedProduct = %s\n", expectedProduct); List<Invoice> invoicesWithProductResult = em.createQuery( "SELECT DISTINCT i " + "FROM Invoice i JOIN i.products p " + "WHERE p.id = :productId ") .setParameter("productId", expectedProduct.getId()) .getResultList(); List<Product> productWithInvoicesResult = em.createQuery( "SELECT DISTINCT p " + "FROM Product p JOIN p.invoices i " + "WHERE p.id = :productId ") .setParameter("productId", expectedProduct.getId()) .getResultList(); utx.commit(); System.out.printf("**** invoicesWithProductResult = %s\n", invoicesWithProductResult); System.out.printf("**** productWithInvoicesResult = %s\n", productWithInvoicesResult ); // Asserts for ( Product prod: products) { assertTrue( prod.getId() > 0 ); } // Asserts for ( Invoice inv: invoices) { assertTrue( inv.getId() > 0 ); } assertEquals(2, invoicesWithProductResult.size()); for ( Invoice inv: invoicesWithProductResult ) { System.out.printf("invoicesWithProductResult = %s\n", inv ); int count = 0; assertTrue(inv.getProducts().contains(expectedProduct)); for ( Product p: inv.getProducts() ) { System.out.printf(" .product[%d] = %s\n", count, p ); assertTrue( "Broken relationship invoice -> products -> invoice", p.getInvoices().contains(inv) ); ++count; } } assertEquals( 1, productWithInvoicesResult.size()); for ( Product prod: productWithInvoicesResult ) { System.out.printf("productWithInvoicesResult = %s\n", prod ); int count = 0; assertEqualsOnCollectionsAnyOrder(expectedInvoices, prod.getInvoices()); for ( Invoice inv: prod.getInvoices() ) { System.out.printf(" .invoices[%d] = %s\n", count, inv ); assertTrue( "Broken inverse relationship product -> invoices -> product", inv.getProducts().contains(prod) ); ++count; } } } @Test public void shouldPersistManyProductWithOneInvoices() throws Exception { // Assign createEntities(); Invoice expectedInvoice = invoices.get(3); List<Product> expectedProducts = Arrays.asList(products.get(0), products.get(1), products.get(3)); expectedInvoice.getProducts().add( products.get(0)); expectedInvoice.getProducts().add( products.get(1)); expectedInvoice.getProducts().add( products.get(3)); products.get(0).getInvoices().add( expectedInvoice); products.get(1).getInvoices().add( expectedInvoice); products.get(3).getInvoices().add( expectedInvoice); // Act utx.begin(); for ( Product prod: products) { em.persist(prod); } for ( Invoice inv: invoices) { em.persist(inv); } utx.commit(); System.out.printf("products = %s\n", products ); System.out.printf("invoices = %s\n", invoices ); // + 44(0) 1732 462801 utx.begin(); System.out.printf("expectedInvoice = %s\n", expectedInvoice); List<Invoice> invoicesWithProductResult = em.createQuery( "SELECT DISTINCT i " + "FROM Invoice i JOIN i.products p " + "WHERE i.id = :invoiceId ") .setParameter("invoiceId", expectedInvoice.getId()) .getResultList(); List<Product> productWithInvoicesResult = em.createQuery( "SELECT DISTINCT p " + "FROM Product p JOIN p.invoices i " + "WHERE i.id = :invoiceId ") .setParameter("invoiceId", expectedInvoice.getId()) .getResultList(); utx.commit(); System.out.printf("**** invoicesWithProductResult = %s\n", invoicesWithProductResult); System.out.printf("**** productWithInvoicesResult = %s\n", productWithInvoicesResult ); // Asserts for ( Product prod: products) { assertTrue( prod.getId() > 0 ); } // Asserts for ( Invoice inv: invoices) { assertTrue( inv.getId() > 0 ); } assertEquals(1, invoicesWithProductResult.size()); for ( Invoice inv: invoicesWithProductResult ) { System.out.printf("invoicesWithProductResult = %s\n", inv ); int count = 0; assertEqualsOnCollectionsAnyOrder(expectedProducts, inv.getProducts()); for ( Product p: inv.getProducts() ) { System.out.printf(" .product[%d] = %s\n", count, p ); assertTrue( "Broken relationship invoice -> products -> invoice", p.getInvoices().contains(inv) ); ++count; } } assertEquals( 3, productWithInvoicesResult.size()); for ( Product prod: productWithInvoicesResult ) { System.out.printf("productWithInvoicesResult = %s\n", prod ); int count = 0; assertTrue(prod.getInvoices().contains(expectedInvoice)); for ( Invoice inv: prod.getInvoices() ) { System.out.printf(" .invoices[%d] = %s\n", count, inv ); assertTrue( "Broken inverse relationship product -> invoices -> product", inv.getProducts().contains(prod) ); ++count; } } } }