| /* |
| * 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.order; |
| |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Random; |
| import java.util.TreeMap; |
| |
| import javax.persistence.Query; |
| |
| import org.apache.openjpa.jdbc.conf.JDBCConfiguration; |
| import org.apache.openjpa.jdbc.meta.ClassMapping; |
| import org.apache.openjpa.jdbc.meta.FieldMapping; |
| import org.apache.openjpa.jdbc.schema.Column; |
| import org.apache.openjpa.jdbc.sql.DBDictionary; |
| import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; |
| import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI; |
| import org.apache.openjpa.persistence.test.SingleEMFTestCase; |
| |
| public class TestOrderColumn extends SingleEMFTestCase { |
| |
| private Student[] students = new Student[12]; |
| |
| @Override |
| public void setUp() { |
| super.setUp( |
| CLEAR_TABLES, |
| Person.class, Player.class, BattingOrder.class, |
| Trainer.class, Game.class, Inning.class, |
| Course.class, Student.class, |
| Owner.class, Bicycle.class, Car.class, Home.class, |
| Widget.class,BiOrderMappedByEntity.class, BiOrderEntity.class ); |
| try { |
| createQueryData(); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /* |
| * 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<>(); |
| 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 a |
| * OneToMany relationship |
| */ |
| public void testOneToManyBiDirElementRemoval() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(BiOrderMappedByEntity.class, "bo2mEntities", |
| "bo2mEntities_ORDER"); |
| |
| // Create some data |
| BiOrderMappedByEntity bome = new BiOrderMappedByEntity(); |
| bome.setId(1); |
| List<BiOrderEntity> boea = new ArrayList<>(); |
| for (int i = 0; i < 5; i++) { |
| BiOrderEntity boe = new BiOrderEntity(); |
| boe.setId(i+1); |
| boe.setName("Entity" + i); |
| boe.setEntity(bome); |
| boea.add(boe); |
| bome.addBo2mEntity(boe); |
| } |
| |
| // Persist |
| em.getTransaction().begin(); |
| em.persist(bome); |
| for (BiOrderEntity boe : boea) { |
| em.persist(boe); |
| } |
| em.getTransaction().commit(); |
| em.refresh(bome); |
| em.clear(); |
| |
| // Verify order is correct. |
| BiOrderMappedByEntity newBome = em.find(BiOrderMappedByEntity.class, |
| bome.getId()); |
| assertNotNull(newBome); |
| for (int i = 0; i < 5 ; i++) { |
| assertEquals(newBome.getBo2mEntities().get(i), boea.get(i)); |
| } |
| |
| // Remove an item |
| em.getTransaction().begin(); |
| newBome.getBo2mEntities().get(2).setEntity(null); |
| newBome.removeBo2mEntity(2); |
| boea.remove(2); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| // Simple assertion via find |
| newBome = em.find(BiOrderMappedByEntity.class, bome.getId()); |
| assertNotNull(newBome); |
| assertNotNull(newBome.getBo2mEntities()); |
| assertEquals(boea.size(), newBome.getBo2mEntities().size()); |
| for (int i = 0; i < boea.size() ; i++) { |
| assertEquals(newBome.getBo2mEntities().get(i), (boea.get(i))); |
| } |
| |
| // Stronger assertion via INDEX value |
| validateIndexAndValues(em, "BiOrderMappedByEntity", "bo2mEntities", 0, |
| boea.toArray(), "id", |
| bome.getId()); |
| |
| 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<>(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(); |
| newGame.getRainDates().remove(4); |
| rainDates.remove(4); |
| newGame.getRainDates().remove(2); |
| rainDates.remove(2); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| newGame = em.find(Game.class, game.getId()); |
| assertNotNull(newGame); |
| assertNotNull(newGame.getRainDates()); |
| assertEquals(8, newGame.getRainDates().size()); |
| // Verify the order |
| for (int i = 0; i < newGame.getRainDates().size(); i++) { |
| assertEquals(newGame.getRainDates().get(i).toString(), |
| rainDates.get(i).toString()); |
| } |
| |
| // Stronger assertion via INDEX value |
| validateCollIndexAndValues(em, "Game", "rainDates", 0, |
| newGame.getRainDates().toArray(), "id", |
| newGame.getId()); |
| |
| 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<>(); |
| 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<>(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 |
| */ |
| public void testOneToManyDefault() { |
| 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]; |
| em.getTransaction().begin(); |
| for (int i = 0; i < 10 ; i++) { |
| players[i] = new Player("Player" + i, i); |
| em.persist(players[i]); |
| } |
| em.getTransaction().commitAndResume(); |
| |
| |
| // Add it to the persistent list in reverse order |
| ArrayList<Player> playersArr = new ArrayList<>(); |
| for (int i = 0; i < 10 ; i++) { |
| playersArr.add(players[9 - i]); |
| } |
| |
| // 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[9 - i])); |
| } |
| |
| // Add another entity and check order |
| Player newPlayer = new Player("New Player", 99); |
| |
| em.getTransaction().begin(); |
| newOrder.getBatters().add(9, newPlayer); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| newOrder = em.find(BattingOrder.class, order.id); |
| assertNotNull(newOrder); |
| for (int i = 0; i <= 10 ; i++) { |
| if (i < 9) |
| assertEquals(newOrder.getBatters().get(i), (players[9 - i])); |
| else if (i == 9) |
| assertEquals(newOrder.getBatters().get(i), newPlayer); |
| else if (i == 10) |
| assertEquals(newOrder.getBatters().get(i), players[0]); |
| } |
| |
| em.close(); |
| } |
| |
| /* |
| * Validates use of OrderColumn with OneToMany using a specified |
| * order column name |
| */ |
| public void testOneToManyNamed() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(BattingOrder.class, "pinch_hitters", |
| "pinch_order"); |
| |
| // Create some data |
| Player[] players = new Player[4]; |
| em.getTransaction().begin(); |
| for (int i = 0; i < 4 ; i++) { |
| players[i] = new Player("PinchHitter" + i, i); |
| em.persist(players[i]); |
| } |
| em.getTransaction().commitAndResume(); |
| |
| // Add it to the persistent list in reverse order |
| ArrayList<Player> pinchArr = new ArrayList<>(); |
| for (int i = 0; i < players.length ; i++) { |
| pinchArr.add(players[players.length - 1 - i]); |
| } |
| |
| // Persist the related entities |
| BattingOrder order = new BattingOrder(); |
| order.setPinchHitters(pinchArr); |
| em.persist(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 < players.length ; i++) { |
| assertEquals(newOrder.getPinchHitters().get(i), |
| (players[players.length - 1 - i])); |
| } |
| em.close(); |
| } |
| |
| /* |
| * Validates use of OrderColumn with ManyToMany relationship |
| */ |
| public void testManyToMany() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(Trainer.class, "playersTrained", |
| "trainingOrder"); |
| |
| // Create some data |
| Player[] players = new Player[25]; |
| em.getTransaction().begin(); |
| for (int i = 0; i < players.length ; i++) { |
| players[i] = new Player("TrainedPlayer" + i, i); |
| em.persist(players[i]); |
| } |
| em.getTransaction().commitAndResume(); |
| |
| // Create M2M, add players in reverse insert order to |
| // validate column order |
| Trainer[] trainers = new Trainer[5]; |
| for (int i = 0; i < trainers.length; i++) { |
| trainers[i] = new Trainer("Trainer" + i); |
| ArrayList<Player> trained = new ArrayList<>(); |
| for (int j = ((i * 5) + 4); j >= (i * 5); j--) { |
| trained.add(players[j]); |
| if (players[j].getTrainers() == null) |
| players[j].setTrainers(new ArrayList<Trainer>()); |
| players[j].getTrainers().add(trainers[i]); |
| } |
| trainers[i].setPlayersTrained(trained); |
| em.persist(trainers[i]); |
| } |
| em.getTransaction().commit(); |
| |
| em.clear(); |
| // Verify order is correct. |
| for (int i = 0; i < trainers.length; i++) { |
| Trainer trainer = em.find(Trainer.class, trainers[i].getId()); |
| assertNotNull(trainer); |
| List<Player> trainedPlayers = trainer.getPlayersTrained(); |
| assertNotNull(trainedPlayers); |
| assertEquals(trainedPlayers.size(), 5); |
| for (int j = trainedPlayers.size() - 1; j >=0 ; j--) { |
| assertEquals(trainedPlayers.get(j), |
| (players[(i * 5) + (4 - j)])); |
| } |
| } |
| em.close(); |
| } |
| |
| /* |
| * Validates use of OrderColumn with ManyToMany bi-directional with |
| * both sides of the relationship maintaining order. This test is not |
| * currently run since work is underway to determine the feasiblity of |
| * bi-directional ordering. |
| */ |
| public void validateBiOrderedManyToMany() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(Game.class, "playedIn", |
| "playerOrder"); |
| |
| validateOrderColumnName(Player.class, "gamesPlayedIn", |
| "playedInOrder"); |
| |
| // Create some data |
| Player[] players = new Player[25]; |
| em.getTransaction().begin(); |
| for (int i = 0; i < players.length ; i++) { |
| players[i] = new Player("GamePlayer" + i, i); |
| em.persist(players[i]); |
| } |
| em.getTransaction().commitAndResume(); |
| |
| // Create M2M, add players in reverse insert order to |
| // validate column order |
| Game[] games = new Game[5]; |
| for (int i = 0; i < games.length; i++) { |
| games[i] = new Game(); |
| ArrayList<Player> playedIn = new ArrayList<>(); |
| for (int j = ((i * 5) + 4); j >= (i * 5); j--) { |
| playedIn.add(players[j]); |
| if (players[j].getGamesPlayedIn() == null) |
| players[j].setGamesPlayedIn(new ArrayList<Game>()); |
| players[j].getGamesPlayedIn().add(games[i]); |
| } |
| games[i].setPlayedIn(playedIn); |
| em.persist(games[i]); |
| } |
| em.getTransaction().commit(); |
| |
| em.clear(); |
| // Verify order is correct. |
| for (int i = 0; i < games.length; i++) { |
| Game game = em.find(Game.class, games[i].getId()); |
| assertNotNull(game); |
| List<Player> playedIn = game.getPlayedIn(); |
| assertNotNull(playedIn); |
| assertEquals(playedIn.size(), 5); |
| for (int j = playedIn.size() - 1; j >=0 ; j--) { |
| Player p = playedIn.get(j); |
| assertEquals(p, |
| (players[(i * 5) + (4 - j)])); |
| for (int k = 0; k < p.getGamesPlayedIn().size(); k++) { |
| assertNotNull(p.getGamesPlayedIn()); |
| assertEquals(p.getGamesPlayedIn().get(k), |
| games[k]); |
| } |
| } |
| } |
| em.close(); |
| } |
| |
| /* |
| * Validates use of OrderColumn with ElementCollection of basic |
| * elements |
| */ |
| public void testElementCollectionBasic() { |
| |
| 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<>(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), |
| dates[9-i]); |
| } |
| em.close(); |
| } |
| |
| /* |
| * Validates use of OrderColumn with ElementCollection of Embeddables |
| */ |
| public void testElementCollectionEmbeddables() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| Game game = new Game(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(Game.class, "innings", |
| "inningOrder"); |
| |
| // Create a list of basic types |
| Inning innings[] = new Inning[9]; |
| Collection<Inning> inningCol = new ArrayList<>(); |
| Random rnd = new Random(); |
| for (int i = 8; i >= 0; i--) { |
| innings[i] = new Inning(i, Math.abs(rnd.nextInt()) % 10, |
| Math.abs(rnd.nextInt()) % 10); |
| } |
| // Add in reverse (correct) order |
| for (int i = 8; i >= 0; i--) { |
| inningCol.add(innings[i]); |
| } |
| game.setInnings(inningCol); |
| |
| em.getTransaction().begin(); |
| em.persist(game); |
| em.getTransaction().commit(); |
| |
| em.clear(); |
| |
| Game newGame = em.find(Game.class, game.getId()); |
| assertNotNull(newGame); |
| // Verify the order |
| Inning[] inningArr = (Inning[])game.getInnings(). |
| toArray(new Inning[9]); |
| for (int i = 0; i < 9; i++) { |
| assertEquals(inningArr[i], |
| innings[8-i]); |
| } |
| em.close(); |
| } |
| |
| |
| /* |
| * Validates the use of the updatable on OrderColumn. insertable=false |
| * simply means the order column is omitted from the sql. Having the |
| * appropriate field mapping will enforce that. |
| */ |
| public void testOrderColumnInsertable() { |
| |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| // Create a collection using secondary entities |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(BattingOrder.class, "titles", |
| "titles_ORDER"); |
| |
| validateOrderColumnInsertable(emf, BattingOrder.class, "fixedBatters", |
| false); |
| |
| em.close(); |
| } |
| |
| /* |
| * Validates the use of the updatable on OrderColumn. updatable=false |
| * simply means the order column is omitted from the sql. Having the |
| * appropriate field mapping will enforce that. |
| */ |
| public void testOrderColumnUpdateable() { |
| |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Verify field name is the default via fm |
| validateOrderColumnName(BattingOrder.class, "titles", |
| "titles_ORDER"); |
| |
| validateOrderColumnUpdatable(emf, BattingOrder.class, "titles", |
| false); |
| |
| em.close(); |
| } |
| |
| /* |
| * Validates the use of the OrderColumn with o2o, o2m, m2m relationships |
| * and collection table - with and without join tables. |
| */ |
| public void testOrderColumnTable() { |
| |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| validateOrderColumnTable(emf, Owner.class, "cars", |
| "OC_CAR", "car_o2m_order"); |
| |
| validateOrderColumnTable(emf, Owner.class, "homes", |
| "home_o2m_table", "homes_ORDER"); |
| |
| validateOrderColumnTable(emf, Owner.class, "bikeColl", |
| "bike_table", "bike_coll_order"); |
| |
| validateOrderColumnTable(emf, Owner.class, "widgets", |
| "widget_m2m_table", "widgets_ORDER"); |
| |
| Owner owner = new Owner(); |
| Collection<Car> cars = new ArrayList<>(); |
| Collection<Home> homes = new ArrayList<>(); |
| Collection<Bicycle> bicycles = new ArrayList<>(); |
| Collection<Widget> widgets = new ArrayList<>(); |
| Collection<Owner> owners = new ArrayList<>(); |
| owner.setCars(cars); |
| owner.setHomes(homes); |
| owner.setBikeColl(bicycles); |
| owner.setWidgets(widgets); |
| |
| for (int i = 0; i < 5; i++){ |
| Car car = new Car(2000 + 1, "Make"+i, "Model"+i); |
| car.setOwner(owner); |
| cars.add(car); |
| |
| Home home = new Home(2000 + i); |
| homes.add(home); |
| |
| Bicycle bike = new Bicycle("Brand"+i, "Model"+i); |
| bicycles.add(bike); |
| |
| Widget widget = new Widget("Name"+i); |
| widgets.add(widget); |
| widget.setOwners(owners); |
| } |
| |
| Object[] carArr = cars.toArray(); |
| Object[] homeArr = homes.toArray(); |
| Object[] bikeArr = bicycles.toArray(); |
| Object[] widgetArr = widgets.toArray(); |
| |
| em.getTransaction().begin(); |
| em.persist(owner); |
| em.getTransaction().commit(); |
| String oid = owner.getId(); |
| |
| em.clear(); |
| |
| // Run queries to ensure the query component uses the correct tables |
| validateIndexAndValues(em, "Owner", "cars", 0, |
| carArr, "id", |
| oid); |
| |
| validateIndexAndValues(em, "Owner", "homes", 0, |
| homeArr, "id", |
| oid); |
| |
| validateIndexAndValues(em, "Owner", "widgets", 0, |
| widgetArr, "id", |
| oid); |
| |
| validateIndexAndValues(em, "Owner", "bikeColl", 0, |
| bikeArr, "id", |
| oid); |
| |
| em.close(); |
| } |
| |
| /* |
| * Validates the use of order column (via INDEX) in the predicate of a |
| * JPQL query. |
| */ |
| public void testOrderColumnPredicateQuery() { |
| |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Query and verify the result |
| String queryString = "SELECT w FROM Course c JOIN c.waitList w " + |
| "WHERE c.name = :cname AND INDEX(w) = :widx"; |
| Query qry = em.createQuery(queryString); |
| qry.setParameter("widx", 0); |
| qry.setParameter("cname", "Course B"); |
| Student idx0 = (Student)qry.getSingleResult(); |
| assertNotNull(idx0); |
| assertEquals(idx0, students[10]); |
| |
| qry.setParameter("widx", 1); |
| idx0 = (Student)qry.getSingleResult(); |
| assertNotNull(idx0); |
| assertEquals(idx0, students[11]); |
| |
| qry.setParameter("cname", "Course A"); |
| qry.setParameter("widx", 0); |
| idx0 = (Student)qry.getSingleResult(); |
| assertNotNull(idx0); |
| assertEquals(idx0, students[11]); |
| |
| qry.setParameter("widx", 1); |
| idx0 = (Student)qry.getSingleResult(); |
| assertNotNull(idx0); |
| assertEquals(idx0, students[10]); |
| |
| em.close(); |
| } |
| |
| /* |
| * Validates the use of order column (via INDEX) in the projection of |
| * a JPQL query. |
| */ |
| public void testOrderColumnProjectionQuery() { |
| |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| |
| // Query and verify the result |
| String queryString = "SELECT INDEX(w) FROM Course c JOIN c.waitList w" + |
| " WHERE c.name = :cname ORDER BY w"; |
| Query qry = em.createQuery(queryString); |
| qry.setParameter("cname", "Course A"); |
| List rlist = qry.getResultList(); |
| assertNotNull(rlist); |
| assertEquals(2, rlist.size()); |
| assertEquals(0l, rlist.get(0)); |
| assertEquals(1l, rlist.get(1)); |
| |
| queryString = "SELECT INDEX(w) FROM Course c JOIN c.waitList w" + |
| " WHERE c.name = :cname AND w.name = 'Student11'"; |
| qry = em.createQuery(queryString); |
| qry.setParameter("cname", "Course B"); |
| Long idx = (Long)qry.getSingleResult(); |
| assertNotNull(idx); |
| assertEquals((Long)idx, (Long)1L); |
| |
| em.close(); |
| } |
| |
| /* |
| * Create the data used by the query tests |
| */ |
| private void createQueryData() { |
| OpenJPAEntityManagerSPI em = emf.createEntityManager(); |
| // Add some data |
| for (int i = 0; i < 12; i++) { |
| students[i] = new Student("Student" + i); |
| } |
| Course courseA = new Course("Course A"); |
| Course courseB = new Course("Course B"); |
| |
| HashSet<Course> courses = new HashSet<>(); |
| courses.add(courseA); |
| courses.add(courseB); |
| HashSet<Student> cAstudents = new HashSet<>(); |
| for (int i = 0; i < 5; i++) { |
| cAstudents.add(students[i]); |
| students[i].setCourses(courses); |
| } |
| courseA.setStudents(cAstudents); |
| ArrayList<Student> cAwaitlist = new ArrayList<>(); |
| cAwaitlist.add(students[11]); |
| cAwaitlist.add(students[10]); |
| courseA.setWaitList(cAwaitlist); |
| |
| HashSet<Student> cBstudents = new HashSet<>(); |
| for (int i = 5; i < 10; i++) { |
| cBstudents.add(students[i]); |
| } |
| courseB.setStudents(cBstudents); |
| ArrayList<Student> cBwaitlist = new ArrayList<>(); |
| cBwaitlist.add(students[10]); |
| cBwaitlist.add(students[11]); |
| courseB.setWaitList(cBwaitlist); |
| |
| em.getTransaction().begin(); |
| em.persist(courseA); |
| em.persist(courseB); |
| em.getTransaction().commit(); |
| em.close(); |
| } |
| |
| private void validateIndexAndValues(OpenJPAEntityManagerSPI em, |
| String entity, String indexedCol, int base, Object[] objs, String |
| idField, Object idValue) { |
| String queryString = |
| "SELECT INDEX(b), b FROM " + entity + " a JOIN a." + indexedCol |
| + " b WHERE a." + idField + " = :idVal"; |
| em.clear(); |
| Query qry = em.createQuery(queryString); |
| qry.setParameter("idVal", idValue); |
| List rlist = qry.getResultList(); |
| |
| assertNotNull(rlist); |
| assertEquals(objs.length, rlist.size()); |
| TreeMap<Long, Object> objMap = new TreeMap<>(); |
| for (int i = 0; i < objs.length; i++) |
| { |
| Object[] rvals = (Object[])rlist.get(i); |
| Long idx = (Long)rvals[0]; |
| Object objVal = rvals[1]; |
| objMap.put(idx, objVal); |
| } |
| for (int i = 0; i < objs.length; i++) { |
| Object val = objMap.get(((long) (base + i))); |
| assertEquals(val, objs[i]); |
| } |
| } |
| |
| private void validateCollIndexAndValues(OpenJPAEntityManagerSPI em, |
| String entity, String indexedCol, int base, Object[] objs, String |
| idField, Object idValue) { |
| String queryString = |
| "SELECT INDEX(b), b FROM " + entity + " a, IN(a." + indexedCol |
| + ") b WHERE a." + idField + " = :idVal"; |
| em.clear(); |
| Query qry = em.createQuery(queryString); |
| qry.setParameter("idVal", idValue); |
| List rlist = qry.getResultList(); |
| |
| assertNotNull(rlist); |
| assertEquals(objs.length, rlist.size()); |
| TreeMap<Long, Object> objMap = new TreeMap<>(); |
| for (int i = 0; i < objs.length; i++) |
| { |
| Object[] rvals = (Object[])rlist.get(i); |
| Long idx = (Long)rvals[0]; |
| Object objVal = rvals[1]; |
| objMap.put(idx, objVal); |
| } |
| for (int i = 0; i < objs.length; i++) { |
| Object val = objMap.get(((long) (base + i))); |
| assertEquals(val, objs[i]); |
| } |
| } |
| |
| private void validateOrderColumnName(Class clazz, String fieldName, |
| String columnName) { |
| validateOrderColumnName(emf, clazz, fieldName, columnName); |
| } |
| |
| private Column getOrderColumn(OpenJPAEntityManagerFactorySPI emf1, |
| Class clazz, String fieldName) { |
| JDBCConfiguration conf = (JDBCConfiguration) emf1.getConfiguration(); |
| ClassMapping cls = conf.getMappingRepositoryInstance(). |
| getMapping(clazz, null, true); |
| FieldMapping fm = cls.getFieldMapping(fieldName); |
| Column oc = fm.getOrderColumn(); |
| assertNotNull(oc); |
| return oc; |
| } |
| |
| private void validateOrderColumnName(OpenJPAEntityManagerFactorySPI emf1, |
| Class clazz, String fieldName, String columnName) { |
| Column oc = getOrderColumn(emf1, clazz, fieldName); |
| assertTrue(oc.getName().equalsIgnoreCase(columnName)); |
| } |
| |
| private void validateOrderColumnTable( |
| OpenJPAEntityManagerFactorySPI emf1, |
| Class clazz, String fieldName, String tableName, |
| String columnName) { |
| Column oc = getOrderColumn(emf1, clazz, fieldName); |
| // Verify the oc has the correct table name |
| assertTrue(oc.getTableName().equalsIgnoreCase(tableName)); |
| // Verify the table exists in the db |
| assertTrue(tableAndColumnExists(emf1, null, tableName, null, |
| columnName)); |
| } |
| |
| private void validateOrderColumnUpdatable( |
| OpenJPAEntityManagerFactorySPI emf1, Class clazz, String fieldName, |
| boolean updatable) { |
| Column oc = getOrderColumn(emf1, clazz, fieldName); |
| assertEquals(updatable, !oc.getFlag(Column.FLAG_DIRECT_UPDATE)); |
| } |
| |
| private void validateOrderColumnInsertable( |
| OpenJPAEntityManagerFactorySPI emf1, Class clazz, String fieldName, |
| boolean insertable) { |
| Column oc = getOrderColumn(emf1, clazz, fieldName); |
| assertEquals(insertable, !oc.getFlag(Column.FLAG_DIRECT_INSERT)); |
| } |
| |
| /** |
| * Method to verify a table was created for the given name and schema |
| */ |
| private boolean tableAndColumnExists(OpenJPAEntityManagerFactorySPI emf1, |
| OpenJPAEntityManagerSPI em, String tableName, String schemaName, |
| String columnName) { |
| JDBCConfiguration conf = (JDBCConfiguration) emf1.getConfiguration(); |
| DBDictionary dict = conf.getDBDictionaryInstance(); |
| OpenJPAEntityManagerSPI em1 = em; |
| |
| // If no em supplied, create one |
| if (em1 == null) { |
| em1 = emf1.createEntityManager(); |
| } |
| Connection conn = (Connection)em1.getConnection(); |
| try { |
| DatabaseMetaData dbmd = conn.getMetaData(); |
| // (meta, catalog, schemaName, tableName, conn) |
| Column[] cols = dict.getColumns(dbmd, null, null, |
| tableName, columnName, conn); |
| if (cols != null && cols.length == 1) { |
| Column col = cols[0]; |
| String colName = col.getName(); |
| if (col.getTableName().equalsIgnoreCase(tableName) && |
| (schemaName == null || |
| col.getSchemaName().equalsIgnoreCase(schemaName)) && |
| colName.equalsIgnoreCase(columnName)) |
| return true; |
| } |
| } catch (Throwable e) { |
| fail("Unable to get column information."); |
| } finally { |
| if (em == null) { |
| em1.close(); |
| } |
| } |
| return false; |
| } |
| } |