From e7c3df714b731eeff96af2c3347948aef5020a03 Mon Sep 17 00:00:00 2001 From: Pinaki Poddar Date: Sun, 10 Aug 2008 10:12:37 +0000 Subject: [PATCH] OPENJPA-692: Add Test cases for Bi-directional mapping with JoinTable git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@684443 13f79535-47bb-0310-9956-ffa450edef68 --- .../jdbc/mapping/bidi/Address.java | 80 +++++++++ .../persistence/jdbc/mapping/bidi/Person.java | 87 ++++++++++ .../bidi/TestBiDirectionalJoinTable.java | 159 ++++++++++++++++++ 3 files changed, 326 insertions(+) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Address.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Person.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/TestBiDirectionalJoinTable.java diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Address.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Address.java new file mode 100644 index 000000000..738a2715c --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Address.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.mapping.bidi; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +/** + * Demonstrate usage of a JoinTable for a bi-directional one-to-many mapping. + * + * + * @author Pinaki Poddar + * + */ +@Entity +@Table(name="J_ADDRESS") +public class Address { + @Id + private String phone; + + private String city; + private int zip; + + @ManyToOne + @JoinColumn(table="J_PERSON_ADDRESSES", referencedColumnName="SSN") + private Person person; + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public int getZip() { + return zip; + } + + public void setZip(int zip) { + this.zip = zip; + } + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Person.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Person.java new file mode 100644 index 000000000..5848c2ab2 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/Person.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.mapping.bidi; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.apache.openjpa.jdbc.meta.strats.RelationCollectionTableFieldStrategy; +import org.apache.openjpa.persistence.jdbc.Strategy; + +/** + * Demonstrate usage of a JoinTable for a bi-directional one-to-many mapping. + * + * + * @author Pinaki Poddar + * + */ +@Entity +@Table(name="J_PERSON") +public class Person { + @Id + private long ssn; + + private String name; + + @OneToMany(cascade=CascadeType.ALL) + @JoinTable(name="J_PERSON_ADDRESSES", + joinColumns = @JoinColumn(name="PERSON_SSN", referencedColumnName="SSN"), + inverseJoinColumns = @JoinColumn(name="ADDRESS_PHONE", referencedColumnName="PHONE")) + private Set
addresses = new HashSet
(); + + public long getSsn() { + return ssn; + } + + public Set
getAddresses() { + return addresses; + } + + /** + * Keep bi-directional relation consistent. + */ + public void addAddress(Address address) { + if (addresses == null) + addresses = new HashSet
(); + addresses.add(address); + address.setPerson(this); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public void setSsn(long ssn) { + this.ssn = ssn; + } +} + \ No newline at end of file diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/TestBiDirectionalJoinTable.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/TestBiDirectionalJoinTable.java new file mode 100644 index 000000000..9d30eb663 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/mapping/bidi/TestBiDirectionalJoinTable.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.openjpa.persistence.jdbc.mapping.bidi; + +import java.util.Arrays; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + +import org.apache.openjpa.persistence.OpenJPAPersistence; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +/** + * Tests basic persistence operations on bi-directional mapping that uses a + * JoinTable. + * + * Originally reported as an error which shows that + * a) rows in join table get repeated insert as bi-directional mapping is + * essentially modeled as two uni-directional mapping + * b) update/delete fails with OptimisticExecption because of repeated operation + * on the join table row + * + * Further details available at + * OPENJPA-692 + * and + * Nabble posts + * + * @author Pinaki Poddar + * + */ +public class TestBiDirectionalJoinTable extends SQLListenerTestCase { + private static long SSN = 123456789; + private static String[] PHONES = {"+1-23-456", "+2-34-567", "+3-45-678"}; + private static int ADDRESS_COUNT = PHONES.length; + private static String[] CITIS = {"Berlin", "Paris", "Rome"}; + private static int[] ZIPS = {123456, 234567, 345678}; + + public void setUp() { + super.setUp(CLEAR_TABLES, Person.class, Address.class); + createData(SSN); + sql.clear(); + } + + public void testPersist() { + EntityManager em = emf.createEntityManager(); + Person person = em.find(Person.class, SSN); + assertNotNull(person); + + assertEquals(ADDRESS_COUNT, person.getAddresses().size()); + } + + public void testQuery() { + EntityManager em = emf.createEntityManager(); + String jpql = "select distinct a.city from Person as p, in(p.addresses) a"; + Query query = em.createQuery(jpql); + assertEquals(ADDRESS_COUNT, query.getResultList().size()); + } + + public void testUpdate() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + Person person = em.find(Person.class, SSN); + Address newAddress = new Address(); + newAddress.setPhone("+4-56-789"); + newAddress.setCity("San Francisco"); + person.addAddress(newAddress); + person.setName("Frank"); + em.merge(person); + em.getTransaction().commit(); + + em = emf.createEntityManager(); + Person updated = em.find(Person.class, SSN); + assertEquals("Frank", updated.getName()); + assertEquals(ADDRESS_COUNT+1, updated.getAddresses().size()); + } + + public void testRemove() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + Person person = em.find(Person.class, SSN); + em.remove(person); + em.getTransaction().commit(); + + assertEquals(0, count(Person.class)); + assertEquals(0, count(Address.class)); + assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*"); + } + + public void testSingleDelete() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + String jpql = "delete from Person p where p.ssn=:ssn"; + em.createQuery(jpql).setParameter("ssn", SSN).executeUpdate(); + em.getTransaction().commit(); + + assertEquals(0, count(Person.class)); + assertEquals(0, count(Address.class)); + assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*"); + } + + public void testBulkDelete() { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + String jpql = "delete from Person p"; + em.createQuery(jpql).executeUpdate(); + em.getTransaction().commit(); + + assertEquals(0, count(Person.class)); + assertEquals(0, count(Address.class)); + assertSQL("DELETE FROM .*J_PERSON_ADDRESSES .*"); + } + + /** + * Create a Person with given SSN and fixed number of addresses. + * + * @param ssn + */ + void createData(long ssn) { + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + sql.clear(); + Person person = new Person(); + person.setSsn(SSN); + person.setName("Pinaki"); + for (int i=0; i