Author: fancy
Date: Mon Jan 12 14:16:06 2009
New Revision: 733932

URL: http://svn.apache.org/viewvc?rev=733932&view=rev
Log:
OPENJPA-843 Unnecessary version update on inverse-side of a 1-m relationship
Committing patch provided by Dinkar Rao

Added:
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniDepartment.java
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniEmployee.java
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniVersionTest.java
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiDepartment.java
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiEmployee.java
    
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiVersionTest.java
Modified:
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java?rev=733932&r1=733931&r2=733932&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java
 Mon Jan 12 14:16:06 2009
@@ -144,7 +144,7 @@
                     customs);
             } else if ((dirty = ImplHelper.getUpdateFields(sm)) != null) {
                 update(sm, dirty, (ClassMapping) sm.getMetaData(), rowMgr,
-                    store, customs);
+                    store, customs, false);
             } else if (sm.isVersionUpdateRequired()) {
                 updateIndicators(sm, (ClassMapping) sm.getMetaData(), rowMgr,
                     store, customs, true);
@@ -268,7 +268,7 @@
      */
     protected void update(OpenJPAStateManager sm, BitSet dirty,
         ClassMapping mapping, RowManager rowMgr, JDBCStore store,
-        Collection customs) throws SQLException {
+        Collection customs, boolean updateIndicators) throws SQLException {
         Boolean custom = mapping.isCustomUpdate(sm, store);
         if (!Boolean.FALSE.equals(custom))
             mapping.customUpdate(sm, store);
@@ -279,17 +279,38 @@
         // detect whether any fields in their rows have been modified
         FieldMapping[] fields = mapping.getDefinedFieldMappings();
         for (int i = 0; i < fields.length; i++) {
-            if (dirty.get(fields[i].getIndex())
-                && !bufferCustomUpdate(fields[i], sm, store, customs)) {
-                fields[i].update(sm, store, rowMgr);
+            FieldMapping field = fields[i];
+            if (dirty.get(field.getIndex())
+                && !bufferCustomUpdate(field, sm, store, customs)) {
+                field.update(sm, store, rowMgr);
+                if (!updateIndicators) {
+                    FieldMapping[] inverseFieldMappings =
+                        field.getInverseMappings();
+                    if (inverseFieldMappings.length == 0) {
+                        updateIndicators = true;
+                    }
+                    else {
+                        for (FieldMapping inverseFieldMapping :
+                            inverseFieldMappings) {
+                            if (inverseFieldMapping.getMappedBy() != null) {
+                                updateIndicators = true;
+                                break;
+                            }
+                        }
+                    }
+                }
             }
         }
 
         ClassMapping sup = mapping.getJoinablePCSuperclassMapping();
-        if (sup == null)
-            updateIndicators(sm, mapping, rowMgr, store, customs, false);
+        if (sup == null) {
+            if (updateIndicators) {
+                updateIndicators(sm, mapping, rowMgr, store, customs, false);
+            }
+        }
         else
-            update(sm, dirty, sup, rowMgr, store, customs);
+            update(sm, dirty, sup, rowMgr, store, customs, updateIndicators);
+
         mapping.update(sm, store, rowMgr);
     }
 

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniDepartment.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniDepartment.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniDepartment.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniDepartment.java
 Mon Jan 12 14:16:06 2009
@@ -0,0 +1,69 @@
+/*
+ * 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.jdbc.kernel;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Version;
+
+...@entity
+public class M21UniDepartment {
+
+       @Id     
+       private String deptid;
+       
+       String name;
+       
+       public String getDeptid() {
+        return deptid;
+    }
+
+    public void setDeptid(String deptid) {
+        this.deptid = deptid;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public String getCostCode() {
+        return costCode;
+    }
+
+    public void setCostCode(String costCode) {
+        this.costCode = costCode;
+    }
+
+    @Version
+       private int version;
+       
+       private String costCode;
+
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+}

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniEmployee.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniEmployee.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniEmployee.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniEmployee.java
 Mon Jan 12 14:16:06 2009
@@ -0,0 +1,81 @@
+/*
+ * 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.jdbc.kernel;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Version;
+
+...@entity
+public class M21UniEmployee {
+    
+    @Id    
+    public String empid;
+    
+    @Version
+    private int version;
+    
+    @ManyToOne
+    M21UniDepartment department;
+    
+    public M21UniDepartment getDepartment() {
+        return department;
+    }
+
+    public void setDepartment(M21UniDepartment department) {
+        this.department = department;
+    }
+
+    public String getEmpid() {
+        return empid;
+    }
+
+    public void setEmpid(String empid) {
+        this.empid = empid;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String name;
+    
+    public float salary;
+
+    public float getSalary() {
+        return salary;
+    }
+
+    public void setSalary(float salary) {
+        this.salary = salary;
+    }
+}

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniVersionTest.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniVersionTest.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniVersionTest.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M21UniVersionTest.java
 Mon Jan 12 14:16:06 2009
@@ -0,0 +1,187 @@
+/*
+ * 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.jdbc.kernel;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class M21UniVersionTest extends SingleEMFTestCase {
+    public static String SALESID = "SALES";
+    public static String MARKETINGID = "MARKETING";
+    
+    public static String EMPLOYEE1ID = "EMPLOYEE1";
+    public static String EMPLOYEE2ID = "EMPLOYEE2";
+    public static String EMPLOYEE3ID = "EMPLOYEE3";
+    
+    
+    public void setUp() {
+        setUp(
+                M21UniDepartment.class, 
+                M21UniEmployee.class,
+                CLEAR_TABLES);        
+        
+        createEntities();        
+    }
+    
+    void createEntities() {        
+        EntityManager em = emf.createEntityManager();
+        
+        em.getTransaction().begin();
+        M21UniDepartment sales = new M21UniDepartment();
+        sales.setDeptid(SALESID);        
+        sales.setName("SALES");
+        sales.setCostCode("1000");
+        M21UniDepartment marketing = new M21UniDepartment();
+        marketing.setDeptid(MARKETINGID);        
+        marketing.setName("marketing");
+        marketing.setCostCode("3000");        
+        
+        M21UniEmployee e1 = new M21UniEmployee();
+        M21UniEmployee e2 = new M21UniEmployee();
+        e1.setEmpid(EMPLOYEE1ID);
+        e1.setName("Gilgamesh_1");
+        e2.setEmpid(EMPLOYEE2ID);
+        e2.setName("Enkidu_1");
+        e1.setDepartment(sales);
+        e2.setDepartment(sales);
+        
+        em.persist(e1);
+        em.persist(e2);
+        em.persist(sales);
+        em.persist(marketing);
+        em.flush();
+        em.getTransaction().commit();
+        em.close();
+        
+    }
+    
+    public void testNonRelationalFieldInverseSideVersionUpdate() {
+        // Change only non-relation fields on Department.
+        // Version number of Department should be updated.
+        // Version numbers of Employee should not be updated.
+        
+        EntityManager em = emf.createEntityManager();
+        M21UniDepartment sales = em.find(M21UniDepartment.class, SALESID);
+        M21UniEmployee e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        M21UniEmployee e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+        
+        em.getTransaction().begin();
+        sales.setCostCode("1001");
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M21UniDepartment.class, SALESID);
+        e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+        em.close();
+        
+        assertEquals(salesVersionPost, salesVersionPre + 1);
+        assertEquals(e1VersionPost, e1VersionPre);
+        assertEquals(e2VersionPost, e2VersionPre);
+    }
+
+
+    public void testNonRelationalFieldOwnerSideVersionUpdate() {
+        // Change only non-relation fields on Employee.
+        // Version number of Employee should be updated.
+        // Version number of Department should not change.
+        EntityManager em = emf.createEntityManager();
+        M21UniDepartment sales = em.find(M21UniDepartment.class, SALESID);
+        M21UniEmployee e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        M21UniEmployee e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+        
+        em.getTransaction().begin();
+        e1.setName("Gilgamesh_2");
+        e2.setName("Enkidu_2");
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M21UniDepartment.class, SALESID);
+        e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+        em.close();
+        
+        assertEquals(salesVersionPost, salesVersionPre);
+        assertEquals(e1VersionPost, e1VersionPre + 1);
+        assertEquals(e2VersionPost, e2VersionPre + 1);        
+    }
+    
+    public void testRelationalFieldOwnerSideVersionUpdate() {
+        // Assign employees to a new Department. 
+        // Since there is a unidirectional ManyToOne relationship 
+        // from  Employee to Department, only the Employee
+        // version should be updated. Department version
+        // should remain the same as before.
+        
+        EntityManager em = emf.createEntityManager();
+        M21UniDepartment sales = em.find(M21UniDepartment.class, SALESID);
+        M21UniDepartment marketing = em.find(M21UniDepartment.class, 
MARKETINGID);
+        M21UniEmployee e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        M21UniEmployee e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int marketingVersionPre = marketing.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+                
+        em.getTransaction().begin();        
+        e1.setDepartment(marketing);
+        // Don't update e2, so we can check for unchanged
+        // version number for e2.        
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M21UniDepartment.class, SALESID);
+        marketing = em.find(M21UniDepartment.class, MARKETINGID);
+        e1 = em.find(M21UniEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M21UniEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int marketingVersionPost = marketing.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+                
+        em.close();
+        
+        assertEquals(salesVersionPost, salesVersionPre);
+        assertEquals(marketingVersionPost, marketingVersionPre);
+        assertEquals(e1VersionPost, e1VersionPre + 1);
+        assertEquals(e2VersionPost, e2VersionPre);        
+    }
+}

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiDepartment.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiDepartment.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiDepartment.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiDepartment.java
 Mon Jan 12 14:16:06 2009
@@ -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.jdbc.kernel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Version;
+
+...@entity
+public class M2MBiDepartment {
+
+       @Id     
+       private String deptid;
+       
+       String name;
+       
+       @ManyToMany(mappedBy="departments", fetch=FetchType.EAGER)      
+       public Collection<M2MBiEmployee> employees = new 
ArrayList<M2MBiEmployee>();
+       
+       @Version
+    private int version;
+
+    private String costCode;
+
+    public Collection<M2MBiEmployee> getEmployees() {
+        return employees;
+    }
+
+    public void setEmployees(Collection<M2MBiEmployee> employees) {
+        this.employees = employees;
+    }
+
+    public String getDeptid() {
+        return deptid;
+    }
+
+    public void setDeptid(String deptid) {
+        this.deptid = deptid;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public String getCostCode() {
+        return costCode;
+    }
+
+    public void setCostCode(String costCode) {
+        this.costCode = costCode;
+    }
+
+    public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+       
+       
+}

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiEmployee.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiEmployee.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiEmployee.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiEmployee.java
 Mon Jan 12 14:16:06 2009
@@ -0,0 +1,86 @@
+/*
+ * 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.jdbc.kernel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Version;
+
+...@entity
+public class M2MBiEmployee {
+    
+    @Id    
+    public String empid;
+    
+    @Version
+    private int version;
+    
+    @ManyToMany(fetch=FetchType.EAGER)
+    public Collection<M2MBiDepartment> departments = new ArrayList
+        <M2MBiDepartment>();
+    
+    public String name;
+
+    public float salary;
+
+    public Collection<M2MBiDepartment> getDepartments() {
+        return departments;
+    }
+
+    public void setDepartments(Collection<M2MBiDepartment> departments) {
+        this.departments = departments;
+    }
+
+    public String getEmpid() {
+        return empid;
+    }
+
+    public void setEmpid(String empid) {
+        this.empid = empid;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public float getSalary() {
+        return salary;
+    }
+
+    public void setSalary(float salary) {
+        this.salary = salary;
+    }
+}

Added: 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiVersionTest.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiVersionTest.java?rev=733932&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiVersionTest.java
 (added)
+++ 
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/M2MBiVersionTest.java
 Mon Jan 12 14:16:06 2009
@@ -0,0 +1,216 @@
+/*
+ * 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.jdbc.kernel;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class M2MBiVersionTest extends SingleEMFTestCase {
+    public static String SALESID = "SALES";
+    public static String MARKETINGID = "MARKETING";
+    
+    public static String EMPLOYEE1ID = "EMPLOYEE1";
+    public static String EMPLOYEE2ID = "EMPLOYEE2";
+    public static String EMPLOYEE3ID = "EMPLOYEE3";
+    
+    public void setUp() {
+        setUp(
+                M2MBiDepartment.class, 
+                M2MBiEmployee.class,
+                CLEAR_TABLES);        
+        
+        createEntities();        
+    }
+    
+    void createEntities() {        
+        EntityManager em = emf.createEntityManager();
+        
+        em.getTransaction().begin();
+        M2MBiDepartment sales = new M2MBiDepartment();
+        sales.setDeptid(SALESID);        
+        sales.setName("SALES");
+        sales.setCostCode("1000");
+        M2MBiDepartment marketing = new M2MBiDepartment();
+        marketing.setDeptid(MARKETINGID);        
+        marketing.setName("marketing");
+        marketing.setCostCode("3000");        
+        
+        M2MBiEmployee e1 = new M2MBiEmployee();
+        M2MBiEmployee e2 = new M2MBiEmployee();
+        e1.setEmpid(EMPLOYEE1ID);
+        e1.setName("Gilgamesh_1");
+        e2.setEmpid(EMPLOYEE2ID);
+        e2.setName("Enkidu_1");
+        
+        e1.getDepartments().add(sales);
+        e2.getDepartments().add(sales);
+        sales.getEmployees().add(e1);
+        sales.getEmployees().add(e2);
+        
+        em.persist(e1);
+        em.persist(e2);
+        em.persist(sales);
+        em.persist(marketing);
+        em.flush();
+        em.getTransaction().commit();
+        em.close();
+        
+    }
+    
+    public void testNonRelationalFieldInverseSideVersionUpdate() {
+        EntityManager em = emf.createEntityManager();
+        
+        M2MBiDepartment sales = em.find(M2MBiDepartment.class, SALESID);
+        M2MBiEmployee e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        M2MBiEmployee e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+        
+        em.getTransaction().begin();        
+        sales.setCostCode("1001");
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M2MBiDepartment.class, SALESID);
+        e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+        em.close();
+        
+        assertEquals(salesVersionPost, salesVersionPre + 1);
+        assertEquals(e1VersionPost, e1VersionPre);
+        assertEquals(e2VersionPost, e2VersionPre);        
+    
+    }
+    
+    public void testNonRelationalFieldOwnerSideVersionUpdate() {
+        // Change only non-relation fields on Employee.
+        // Version number of Employee should be updated.
+        // Version number of Department should not change.
+        EntityManager em = emf.createEntityManager();
+        M2MBiDepartment sales = em.find(M2MBiDepartment.class, SALESID);
+        M2MBiEmployee e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        M2MBiEmployee e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+        
+        em.getTransaction().begin();
+        e1.setName("Gilgamesh_2");
+        e2.setName("Enkidu_2");
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M2MBiDepartment.class, SALESID);
+        e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+        em.close();
+        
+        assertEquals(salesVersionPost, salesVersionPre);
+        assertEquals(e1VersionPost, e1VersionPre + 1);
+        assertEquals(e2VersionPost, e2VersionPre + 1);        
+    }
+
+    
+    public void testRelationalFieldBothSidesVersionUpdate() {
+        // Move Employee from old Department to new Department.
+        // Update both sides of the relationship.        
+        // Since there is a bidirectional ManyToMany relationship 
+        // from  Employee to Department, Employee version should
+        // be updated. Since neither the new nor the old Departments
+        // are owners of the reassigned Employee, the Department 
+        // versions should remain the same.
+        
+        EntityManager em = emf.createEntityManager();
+        M2MBiDepartment sales = em.find(M2MBiDepartment.class, SALESID);
+        M2MBiDepartment marketing = em.find(M2MBiDepartment.class, 
MARKETINGID);
+        M2MBiEmployee e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        M2MBiEmployee e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPre = sales.getVersion();
+        int marketingVersionPre = marketing.getVersion();
+        int e1VersionPre = e1.getVersion();
+        int e2VersionPre = e2.getVersion();
+        
+        em.getTransaction().begin();
+        // Remove sales from e1
+        Collection<M2MBiDepartment> e1Departments = e1.getDepartments();
+        for (Iterator<M2MBiDepartment> dIterator = e1Departments.iterator(); 
dIterator.hasNext();) {
+            M2MBiDepartment d = dIterator.next();
+            if (SALESID.equals(d.getDeptid())) {
+                dIterator.remove();
+                break;
+            }
+        }
+        // remove e1 from sales
+        Collection<M2MBiEmployee> salesEmployees = sales.getEmployees();
+        for (Iterator<M2MBiEmployee> eIterator = salesEmployees.iterator(); 
eIterator.hasNext();) {
+            M2MBiEmployee e = eIterator.next();
+            if (EMPLOYEE1ID.equals(e.getEmpid())) {
+                eIterator.remove();
+                break;
+            }
+        }
+        
+        // Add marketing to e1
+        e1.getDepartments().add(marketing);
+        // Add e1 to marketing
+        marketing.getEmployees().add(e1);
+        
+        em.getTransaction().commit();
+        em.close();
+        
+        em = emf.createEntityManager();
+        sales = em.find(M2MBiDepartment.class, SALESID);
+        marketing = em.find(M2MBiDepartment.class, MARKETINGID);
+        e1 = em.find(M2MBiEmployee.class, EMPLOYEE1ID);
+        e2 = em.find(M2MBiEmployee.class, EMPLOYEE2ID);
+        
+        int salesVersionPost = sales.getVersion();
+        int marketingVersionPost = marketing.getVersion();
+        int e1VersionPost = e1.getVersion();
+        int e2VersionPost = e2.getVersion();
+        em.close();
+        
+        // Since Department is inverse side, there should
+        // be no version update when its employees are moved.
+        assertEquals(salesVersionPost, salesVersionPre);
+        assertEquals(marketingVersionPost, marketingVersionPre);
+        // Employee e1 was moved to marketing.
+        assertEquals(e1VersionPost, e1VersionPre + 1);
+        // Employee e2 was unchanged.
+        assertEquals(e2VersionPost, e2VersionPre);        
+    }
+}


Reply via email to