Author: jrbauer
Date: Fri May  8 19:53:16 2009
New Revision: 773070

URL: http://svn.apache.org/viewvc?rev=773070&view=rev
Log:
OPENJPA-1074 Maintain contiguous index for collection element removal

Modified:
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerCollectionTableFieldStrategy.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/order/TestOrderColumn.java

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerCollectionTableFieldStrategy.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerCollectionTableFieldStrategy.java?rev=773070&r1=773069&r2=773070&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerCollectionTableFieldStrategy.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/HandlerCollectionTableFieldStrategy.java
 Fri May  8 19:53:16 2009
@@ -197,8 +197,12 @@
                 ct = proxy.getChangeTracker();
         }
 
-        // if no fine-grained change tracking then just delete and reinsert
-        if (ct == null || !ct.isTracking()) {
+        Column order = field.getOrderColumn();
+
+        // if no fine-grained change tracking or if an item was removed
+        // from an ordered collection, delete and reinsert
+        if (ct == null || !ct.isTracking() ||
+            (order != null && !ct.getRemoved().isEmpty())) {
             delete(sm, store, rm);
             insert(sm, store, rm, obj);
             return;
@@ -227,7 +231,6 @@
                 field.getJoinColumnIO(), sm);
 
             int seq = ct.getNextSequence();
-            Column order = field.getOrderColumn();
             boolean setOrder = field.getOrderColumnIO().isInsertable(order,
                 false);
             for (Iterator itr = add.iterator(); itr.hasNext(); seq++) {

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java?rev=773070&r1=773069&r2=773070&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationToManyTableFieldStrategy.java
 Fri May  8 19:53:16 2009
@@ -186,8 +186,12 @@
                 ct = proxy.getChangeTracker();
         }
 
-        // if no fine-grained change tracking then just delete and reinsert
-        if (ct == null || !ct.isTracking()) {
+        Column order = field.getOrderColumn();
+
+        // if no fine-grained change tracking or if an item was removed
+        // from an ordered collection, delete and reinsert
+        if (ct == null || !ct.isTracking() ||
+            (order != null && !ct.getRemoved().isEmpty())) {
             delete(sm, store, rm);
             insert(sm, rm, obj);
             return;
@@ -220,7 +224,6 @@
                 field.getJoinColumnIO(), sm);
 
             int seq = ct.getNextSequence();
-            Column order = field.getOrderColumn();
             boolean setOrder = field.getOrderColumnIO().isInsertable(order,
                 false);
             for (Iterator itr = add.iterator(); itr.hasNext(); seq++) {

Modified: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/order/TestOrderColumn.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/order/TestOrderColumn.java?rev=773070&r1=773069&r2=773070&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/order/TestOrderColumn.java
 (original)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/order/TestOrderColumn.java
 Fri May  8 19:53:16 2009
@@ -75,6 +75,266 @@
     }
 
     /*
+     * Verifies that a collection remains contiguous and element
+     * indexes are reordered if an element is removed for a
+     * OneToMany relationship 
+     */
+    public void testOneToManyElementRemoval() {
+        OpenJPAEntityManagerSPI em = emf.createEntityManager();
+
+        // Verify field name is the default via fm
+        validateOrderColumnName(BattingOrder.class, "batters", 
+            "batters_ORDER");// "batters_ORDER");
+
+        // Create some data
+        Player[] players = new Player[10];
+        ArrayList<Player> playersArr = new ArrayList<Player>();
+        em.getTransaction().begin();
+        for (int i = 0; i < 10 ; i++) {
+            players[i] = new Player("Player" + i, i+100);
+            em.persist(players[i]);
+            playersArr.add(players[i]);
+        }
+        em.getTransaction().commitAndResume();
+                      
+        // Persist the related entities
+        BattingOrder order = new BattingOrder();
+        order.setBatters(playersArr);
+        em.persist(order);
+        em.getTransaction().commit();
+        em.refresh(order);
+        em.clear();
+        
+        // Verify order is correct.
+        BattingOrder newOrder = em.find(BattingOrder.class, order.id);
+        assertNotNull(newOrder);
+        for (int i = 0; i < 10 ; i++) {
+            assertEquals(newOrder.getBatters().get(i), (players[i]));
+        }
+        
+        // Remove some items
+        em.getTransaction().begin();
+        newOrder.getBatters().remove(1);
+        playersArr.remove(1);
+        newOrder.getBatters().remove(5);
+        playersArr.remove(5);        
+        em.getTransaction().commit();
+        em.clear();
+
+        // Simple assertion via find
+        newOrder = em.find(BattingOrder.class, order.id);
+        assertNotNull(newOrder);
+        assertNotNull(newOrder.getBatters());
+        assertEquals(playersArr.size(), newOrder.getBatters().size());
+        for (int i = 0; i < playersArr.size() ; i++) {
+              assertEquals(newOrder.getBatters().get(i), (playersArr.get(i)));
+        }
+
+        // Stronger assertion via INDEX value
+        validateIndexAndValues(em, "BattingOrder", "batters", 0, 
+            playersArr.toArray(), "id", 
+            order.id);
+        
+        em.close();        
+    }
+
+    /*
+     * Verifies that a collection remains contiguous and element
+     * indexes are reordered if an element is removed for an
+     * ElementCollection 
+     */
+    public void testElementCollectionElementRemoval() {
+        OpenJPAEntityManagerSPI em = emf.createEntityManager();
+        Game game = new Game();
+        
+        // Verify field name is the default via fm
+        validateOrderColumnName(Game.class, "rainDates", 
+            "dateOrder"); 
+        
+        // Create a list of basic types
+        java.sql.Date dates[] = new java.sql.Date[10];
+        ArrayList<java.sql.Date> rainDates = new ArrayList<java.sql.Date>(10);
+        Calendar today = Calendar.getInstance();
+        for (int i = 0; i < 10; i++) {
+            today.set(2009, 1, i+1);
+            dates[i] = new java.sql.Date(today.getTimeInMillis());
+        }
+        // Add in reverse order
+        for (int i = 9; i >= 0; i--) {
+            rainDates.add(dates[i]);
+        }
+        game.setRainDates(rainDates);
+        
+        em.getTransaction().begin();
+        em.persist(game);
+        em.getTransaction().commit();
+               
+        em.clear();
+        
+        Game newGame = em.find(Game.class, game.getId());
+        assertNotNull(newGame);
+        // Verify the order
+        for (int i = 0; i < 10; i++) {
+            assertEquals(game.getRainDates().get(i),
+                rainDates.get(i));
+        }
+        
+        // Remove some dates
+        em.getTransaction().begin();
+        game.getRainDates().remove(4);
+        rainDates.remove(4);
+        game.getRainDates().remove(2);
+        rainDates.remove(2);
+        em.getTransaction().commit();
+        em.clear();
+
+        newGame = em.find(Game.class, game.getId());
+        assertNotNull(newGame);
+        assertNotNull(game.getRainDates());
+        assertEquals(8, game.getRainDates().size());
+        // Verify the order
+        for (int i = 0; i < game.getRainDates().size(); i++) {
+            assertEquals(game.getRainDates().get(i),
+                rainDates.get(i));
+        }
+        
+        em.close();
+    }
+    /*
+     * Verifies that a collection remains contiguous and element
+     * indexes are reordered if an element is inserted into the collection. 
+     */
+    public void testOneToManyElementInsert() {
+        OpenJPAEntityManagerSPI em = emf.createEntityManager();
+
+        // Verify field name is the default via fm
+        validateOrderColumnName(BattingOrder.class, "batters", 
+            "batters_ORDER");// "batters_ORDER");
+
+        // Create some data
+        Player[] players = new Player[10];
+        ArrayList<Player> playersArr = new ArrayList<Player>();
+        em.getTransaction().begin();
+        for (int i = 0; i < 10 ; i++) {
+            players[i] = new Player("Player" + i, i+100);
+            em.persist(players[i]);
+            playersArr.add(players[i]);
+        }
+        em.getTransaction().commitAndResume();
+                      
+        // Persist the related entities
+        BattingOrder order = new BattingOrder();
+        order.setBatters(playersArr);
+        em.persist(order);
+        em.getTransaction().commitAndResume();
+        em.refresh(order);
+        
+        em.getTransaction().commit();
+        em.clear();
+        
+        // Verify order is correct.
+        BattingOrder newOrder = em.find(BattingOrder.class, order.id);
+        assertNotNull(newOrder);
+        for (int i = 0; i < 10 ; i++) {
+            assertEquals(newOrder.getBatters().get(i), (players[i]));
+        }
+                
+        Player p = new Player("PlayerNew", 150);
+        playersArr.add(2, p);
+
+        Player p2 = new Player("PlayerNew2", 151);
+        playersArr.add(p2);
+        // Add an item at index 2 and at the end of the list 
+        em.getTransaction().begin();
+        newOrder.getBatters().add(2, p);
+        newOrder.getBatters().add(p2);
+        em.getTransaction().commit();
+        em.clear();
+
+        // Simple assertion via find
+        newOrder = em.find(BattingOrder.class, order.id);
+        assertNotNull(newOrder);
+        assertNotNull(newOrder.getBatters());
+        assertEquals(playersArr.size(), newOrder.getBatters().size());
+        for (int i = 0; i < playersArr.size() ; i++) {
+              assertEquals(newOrder.getBatters().get(i), (playersArr.get(i)));
+        }
+
+        // Stronger assertion via INDEX value
+        validateIndexAndValues(em, "BattingOrder", "batters", 0, 
+            playersArr.toArray(), "id", 
+            order.id);
+        
+        em.close();        
+    }
+    /*
+     * Verifies that a collection remains contiguous and element
+     * indexes are reordered if an element is inserted into an
+     * ElementCollection 
+     */
+    public void testElementCollectionElementInsert() {
+        OpenJPAEntityManagerSPI em = emf.createEntityManager();
+        Game game = new Game();
+        
+        // Verify field name is the default via fm
+        validateOrderColumnName(Game.class, "rainDates", 
+            "dateOrder"); 
+        
+        // Create a list of basic types
+        java.sql.Date dates[] = new java.sql.Date[10];
+        ArrayList<java.sql.Date> rainDates = new ArrayList<java.sql.Date>(10);
+        Calendar today = Calendar.getInstance();
+        for (int i = 0; i < 10; i++) {
+            today.set(2009, 1, i+1);
+            dates[i] = new java.sql.Date(today.getTimeInMillis());
+        }
+        // Add in reverse order
+        for (int i = 9; i >= 0; i--) {
+            rainDates.add(dates[i]);
+        }
+        game.setRainDates(rainDates);
+        
+        em.getTransaction().begin();
+        em.persist(game);
+        em.getTransaction().commit();
+               
+        em.clear();
+        
+        Game newGame = em.find(Game.class, game.getId());
+        assertNotNull(newGame);
+        // Verify the order
+        for (int i = 0; i < 10; i++) {
+            assertEquals(game.getRainDates().get(i),
+                rainDates.get(i));
+        }
+        
+        // Add some dates
+        today.set(2009, 1, 15);
+        rainDates.add(1, new java.sql.Date(today.getTimeInMillis()));
+        today.set(2009, 1, 20);
+        rainDates.add(6, new java.sql.Date(today.getTimeInMillis()));
+        
+        em.getTransaction().begin();
+        game.getRainDates().add(1, rainDates.get(1));
+        game.getRainDates().add(6, rainDates.get(6));
+        em.getTransaction().commit();
+        em.clear();
+
+        newGame = em.find(Game.class, game.getId());
+        assertNotNull(newGame);
+        assertNotNull(game.getRainDates());
+        assertEquals(12, game.getRainDates().size());
+        // Verify the order
+        for (int i = 0; i < game.getRainDates().size(); i++) {
+            assertEquals(game.getRainDates().get(i),
+                rainDates.get(i));
+        }
+        
+        em.close();
+    }
+
+    
+    /*
      * Validates use of OrderColumn with OneToMany using the default
      * order column name
      */
@@ -851,7 +1111,7 @@
         List rlist = qry.getResultList();  
         
         assertNotNull(rlist);
-        assertEquals(rlist.size(), objs.length); 
+        assertEquals(objs.length, rlist.size()); 
         TreeMap<Long, Object> objMap = new TreeMap<Long, Object>();
         for (int i = 0; i < objs.length; i++)
         {


Reply via email to