package org.javaee7.jpa.ordercolumn; import static org.junit.Assert.assertEquals; import javax.ejb.EJB; import javax.persistence.OrderColumn; import org.javaee7.jpa.ordercolumn.entity.bidirectionalmappedby.Child; import org.javaee7.jpa.ordercolumn.entity.bidirectionalmappedby.Parent; import org.javaee7.jpa.ordercolumn.service.bidirectionalmappedby.OrderColumnTesterService; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Test; import org.junit.runner.RunWith; /** * This tests and demonstrates the {@link OrderColumn} annotation when used together with a * bi-directional parent-child mapping, where the child holds a foreign key to the parent. * * <p> * This is the normal oneToMany mapping using the <code>mappedBy</code> attribute. * Even though this is the most straightforward mapping, because of a mis-interpretation * in the JPA spec it was believed for years that this mapping did not have to be * supported (see https://hibernate.atlassian.net/browse/HHH-5732 among others) * * <p> * In this mapping the position each child has in the parent's list is stored in the * child table and fully managed by JPA. This means that this position index does * not explicitly show up in the object model. * * <p> * Example SQL DDL (h2 syntax) * <pre> * create table Parent ( * id bigint generated by default as identity, * * primary key (id) * ); * * create table Child ( * id bigint generated by default as identity, * parent_id bigint, * children_ORDER integer, * * primary key (id), * foreign key (parent_id) references Parent * ); * </pre> * * * @author Arjan Tijms */ @RunWith(Arquillian.class) public class OrderColumnBiMappedByTest { @Deployment private static Archive<?> createDeployment() { return ShrinkWrap.create(WebArchive.class) .addPackages(true, Parent.class.getPackage()) .addPackages(true, OrderColumnTesterService.class.getPackage()) .addAsResource("META-INF/persistence.xml"); } @EJB private OrderColumnTesterService indexColumnTesterService; @Test public void saveInOneGo() { Parent parent = new Parent(); Child child1 = new Child(); child1.setParent(parent); Child child2 = new Child(); child2.setParent(parent); parent.getChildren().add(child1); parent.getChildren().add(child2); parent = indexColumnTesterService.save(parent); Parent savedParent = indexColumnTesterService.getParentById(parent.getId()); assertEquals("2 children added to parent and saved, but after re-loading number of chilren different", 2, savedParent.getChildren().size()); } /** * Saves a parent instance first, then adds two children instances and saves again. * * <p> * Example sequence of insert/update statements that may be generated to accomplish this: * <pre> * insert into Parent (id) values (null) * insert into Child (id, parent_id) values (null, 1) * insert into Child (id, parent_id) values (null, 1) * * update Child set children_ORDER = 0 where id = 1 * update Child set children_ORDER = 1 where id = 2 * </pre> * */ @Test public void saveParentSeparatelyFirst() { Parent parent = indexColumnTesterService.save(new Parent()); Child child1 = new Child(); child1.setParent(parent); Child child2 = new Child(); child2.setParent(parent); parent.getChildren().add(child1); parent.getChildren().add(child2); parent = indexColumnTesterService.save(parent); Parent savedParent = indexColumnTesterService.getParentById(parent.getId()); assertEquals("2 children added to parent and saved, but after re-loading number of chilren different", 2, savedParent.getChildren().size()); } }