JPA – Recursive ManyToMany-Relationship

The relationship brother/sister between persons should be implemented. So we have one class APerson which may have 0, 1 or more siblings. This relationship is to model bidirectional.

@Entity
@Table(name = "A_PERSON")
public class APerson implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    @ManyToMany
    @JoinTable(name = "A_SIBLING",
            joinColumns =
                @JoinColumn(name = "SIBLING1", referencedColumnName = "Id"),
            inverseJoinColumns =
                @JoinColumn(name = "SIBLING2", referencedColumnName = "Id"))
    private List<APerson> siblings;
    // Constructors

    // Getter and Setter

    public void addSibling(APerson sibling) {
        siblings.add(sibling);
        if (!sibling.getSiblings().contains(this)) {
            sibling.addSibling(this);
        }
    }
}

This are the jUnit-Tests.

public class APersonTest {
    
    private EntityManager em;
    private EntityTransaction tx;
    
    public APersonTest() {
        
    }
    
    @BeforeClass
    public static void setUpClass() {    }
    
    /**
     *  Am Ende aller Tests wird die EntityManagerFactory geschlossen
     */
    @AfterClass
    public static void tearDownClass() {
        JpaUtil.shutdown();
    }
    
    @Before
    public void setUp() {
        // using the DerbyDb in network mode
        // em = JpaUtil.getEntityManager("KfzSeTestPU");
        // using the DerbyDb in memory mode
        em = JpaUtil.getEntityManager();
        tx = em.getTransaction();
    }
    
    @After
    public void tearDown() {
        em.close();
    }

    @Test
    public void test01CreatePersons() {
        APerson hans = new APerson("Hans");
        APerson susi = new APerson("Susi");
        tx.begin();
        em.persist(hans);
        em.persist(susi);
        tx.commit();
        assertNotNull(hans.getId());
        assertNotNull(susi.getId());
        
        // using JP-QL there is NO transaction necessary
        long anzahlPersonen   // der Rückgabetyp von COUNT() ist Long
                = em.createQuery("select COUNT(p) from APerson p", Long.class)
                    .getSingleResult();
        assertEquals(2L, anzahlPersonen);
    }
    
    @Test
    public void test02CreateSiblings() {
        APerson hans = em.createQuery("select p from APerson p where p.name = ?1", APerson.class)
                .setParameter(1, "Hans")
                .getSingleResult();
        APerson susi = em.createQuery("select p from APerson p where p.name = ?1", APerson.class)
                .setParameter(1, "Susi")
                .getSingleResult();
        
        hans.addSibling(susi);
        tx.begin();
        em.persist(hans);
        tx.commit();
        
        assertEquals("Hans", susi.getSiblings().get(0).getName());
        assertEquals("Susi", hans.getSiblings().get(0).getName());
    }

    @Test
    public void test03CreateThreeSiblings() {
        APerson hans = em.createQuery("select p from APerson p where p.name = ?1", APerson.class)
                .setParameter(1, "Hans")
                .getSingleResult();
        APerson susi = em.createQuery("select p from APerson p where p.name = ?1", APerson.class)
                .setParameter(1, "Susi")
                .getSingleResult();
        
        APerson maxi = new APerson("Maxi");
        
        tx.begin();
        maxi.addSibling(susi);
        maxi.addSibling(hans);
        em.persist(maxi);
        tx.commit();
        
        long anzahlPersonen   
                = em.createQuery("select COUNT(p) from APerson p", Long.class)
                    .getSingleResult();
        assertEquals(3L, anzahlPersonen);
    }
}

The ManyToMany-Relationship creates 2 tables:
Bildschirmfoto 2013-10-19 um 22.35.37

Bildschirmfoto 2013-10-19 um 22.35.09

Bildschirmfoto 2013-10-19 um 22.34.49

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment