The following comment has been added to this issue: Author: Gavin King Created: Wed, 22 Oct 2003 5:12 PM Body: This code is completely un-runnable! Missing mapping files and all kinds of problems. Not to mention that your session handling is completely bizarre. I suggest you spend some time looking for a bug in your code instead of blaming Hibernate. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Unassigned Priority: Major Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 4:52 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: Gavin King Created: Wed, 22 Oct 2003 4:45 PM Body: I need something that is actually runnable. I don't understand this code at all. What on earth are all the useless-looking calls to saveOrUpdate() for?? The object is already associated with the session! --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Unassigned Priority: Major Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 4:41 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: David Duffy Created: Wed, 22 Oct 2003 6:43 PM Body: What!? I built it with Ant 1.5.3 without incident, I ran it without incident, standalone, by itself, and got the error as expected. Then I zipped the entire src directory which contains ALL of the mapping files, including hibernate.cfg.xml and hibernate.properties (they are in the tests package with the testcase instead of the root). Would you like my build file too? I suspect that you compiled into some kind of "build" directory and your build didn't copy the xml files over with the classes. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Closed Priority: Major Resolution: REJECTED Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 5:15 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: David Duffy Created: Wed, 22 Oct 2003 7:05 PM Body: Oh, and one more thing, I've litterally spent days isolating the problem down, stepping through all of my code and a lot of Hibernate's code. I may not know how to use Hibernate as well as I would like (and you must admit there is quite a learning curve, especially when under the pressures of dealines) but I make sure to the best of my ability to rule out problems in my own code before ever broaching the question about what is happening in Hibernate. This problem is not a result of "my code", it may be a result of my using Hibernate wrong, but as you can see from the forum discussion I first asked if that was the case and explained what I was doing, why, and what was happening. The consesus there was that Hibernate should not be putting a duplicate instance into the bag as a result of the call to saveOrUpdate. I tried stepping through Hibernate's code to see if I could figure out at what point during the saveOrUpdate call the duplicate instance got added and why but I did not succeed in that task, I did however succeed in determining that calling the .size() method on the bag causes what I called re-initialization of the collection and then saveOrUpdate does not add a duplicate instance. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Closed Priority: Major Resolution: REJECTED Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 5:15 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: Gavin King Created: Thu, 23 Oct 2003 12:28 AM Body: Nevertheless, you did not isolate the problem. If you are correct, this problem must be reproduceable with 2 classes and presumably about 10-20 lines of Hibernate code. I have a very strong suspicion that if you try to strip your example down to that, you will discover the cause for yourself. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Closed Priority: Major Resolution: REJECTED Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 5:15 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: David Duffy Created: Wed, 22 Oct 2003 6:47 PM Body: As for stripped down to a few calls... there are only two calls in question: "bag".size(); and saveOrUpdate(); Without the first one the duplication occurs, with the first one some kind of re-initialization occurs which "prevents" the saveOrUpdate from adding the dupliate instance. Everything else is just setup and teardown, I'm sorry my model is complex but that's what is required of the app and that is where the problem occurs. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Closed Priority: Major Resolution: REJECTED Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 5:15 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |
The following comment has been added to this issue: Author: David Duffy Created: Wed, 22 Oct 2003 4:59 PM Body: Sorry, I should mention that the test case main method is in com/fgl/ina/tests/HibernateTest. Also, the "useless-looking" calls to saveOrUpdate are two fold; 1) they serve to save the convoluted object hierarchy in stages because I still don't understand how to do things properly and I have some really screwy code still kicking around from when I understood even less, and 2) they serve to mimic the MVC stages that happen in my app where I am having the issue. --------------------------------------------------------------------- View the issue: http://opensource.atlassian.com/projects/hibernate/secure/ViewIssue.jspa?key=HB-420 Here is an overview of the issue: --------------------------------------------------------------------- Key: HB-420 Summary: Adding a new instance to a persistent bag and calling saveOrUpdate adds a duplicate instance to the bag but not the DB. Type: Bug Status: Unassigned Priority: Major Project: Hibernate2 Components: core Versions: 2.1 beta 3 2.1 beta 4 Assignee: Reporter: David Duffy Created: Wed, 22 Oct 2003 3:27 PM Updated: Wed, 22 Oct 2003 4:52 PM Environment: JDK1.4.2, Windows 2003 Server; JDK1.4.2, Windows 2000; JDK1.3.1 Windows 2000 Description: When a new (transient) instance of a persisted child is created and added to the "bag" of children on the parent and then the parent is re-persisted via Session.saveOrUpdate() a second instance of the child will be added to the "bag" but not to the database. However, calling the .size() method on the "bag" before calling saveOrUpdate() will cause the problem to disappear. A unit test class that demonstrates this is as follows: package com.fgl.ina.tests; import junit.framework.TestCase; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Session; import net.sf.hibernate.LockMode; import java.net.URL; import java.util.Properties; import java.util.ArrayList; //import java.util.Map; import java.util.Iterator; import java.io.BufferedInputStream; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import com.fgl.ina.stylecreation.Product; //import com.fgl.ina.stylecreation.details.ProductDescription; import com.fgl.ina.stylecreation.barcodes.ProductBarcode; import com.fgl.ina.stylecreation.lookups.BarcodeType; import com.fgl.ina.stylecreation.coloursize.ProductColourSizeHelper; import com.fgl.ina.stylecreation.coloursize.ProductColourAndSize; import com.fgl.ina.services.DataAccessService; import com.fgl.ina.mastertables.colours.Colour; import com.fgl.ina.mastertables.sizes.Size; /** * Tests Hibernate (sort of), or at least aspects that are of immediate concern at time of writing. * @author David Duffy */ public class HibernateTest extends TestCase { //TODO: make a test suite (or whatever it is) that will do the setup and teardown only once for all Hibernate tests private static final Log log = LogFactory.getLog(HibernateTest.class); private static final String TEST_CONFIG_PATH = "/com/fgl/ina/tests/hibernatetest.cfg.xml"; private static final String TEST_PROPERTIES_PATH = "/com/fgl/ina/tests/hibernatetest.properties"; private SessionFactory factory; public HibernateTest(String testName) { super(testName); } /** * Perform unit test set up before running test(s). */ protected void setUp() { Configuration configuration = null; URL configFileURL = null; try { configFileURL = Class.class.getResource(TEST_CONFIG_PATH); if (log.isDebugEnabled()) { log.debug("Initializing Hibernate from " + TEST_CONFIG_PATH + "..."); } BufferedInputStream bis = new BufferedInputStream(Class.class.getResourceAsStream(TEST_PROPERTIES_PATH)); Properties properties = new Properties(); properties.load(bis); bis.close(); configuration = (new Configuration().setProperties(properties)).configure(configFileURL); factory = configuration.buildSessionFactory(); } catch (Throwable t) { log.error("Exception while initializing Hibernate.", t); } } /** * Perform unit test tear down after running test(s). */ protected void tearDown() { try { if (factory != null) { factory.close(); } } catch (Throwable t) { log.error("Couldn't close session factory", t); } } // TODO: make setup/teardown do the supporting object creation when there is a suite that does the Hibernate config public void testAddingBarcodes() throws Exception { if (factory == null) { fail("SessionFactory == null"); } else { Session session = factory.openSession(); try { // create a new product, remove its descriptions temporarily and save it without them Product product = new Product(0); product.getDetails().setVendorNumber(1); product.getDetails().setVpn("unittestvpn"); // Map temp = product.getProductDescriptions(); product.setProductDescriptions(null); DataAccessService.saveOrUpdate(session, product); // start building up the colours and sizes... try { // get a valid colour Colour colour = (Colour)DataAccessService.get(session, Colour.class).get(0); // get a valid size Size size = (Size)DataAccessService.get(session, Size.class).get(0); // add the valid colour and size (references) to the product and save the product (again). product.getColours().add(colour); product.getSizes().add(size); DataAccessService.saveOrUpdate(session, product); // create a Collection for colour/size combinations and run the helper method to create the records // for the existing colours and sizes on the product product.setColourSizes(new ArrayList()); ProductColourSizeHelper.createColourSizesForColour(session, product, colour.getColourID()); // save the product now that it has colour and size combinations (in this test there is only one). DataAccessService.saveOrUpdate(session, product); // use this session to load the barcode barcodeType and then close the session. BarcodeType barcodeType = (BarcodeType)DataAccessService.get(session, BarcodeType.class, new Integer(1)); session.flush(); // redundant... session.close(); // open a new session and reload the product so that null Collections will get proxies... session = factory.openSession(); product = (Product)DataAccessService.get(session, Product.class, new Integer(product.getProductID())); session.close(); // get a new session so that the product instance spans multiple sessions just like in the real // scenario being debugged... session = factory.openSession(); // lock the product to the new session to reassociate it with the new session session.lock(product, LockMode.UPGRADE); // grab the colour and size combination, create a new barcode, and add it to the colour/size. ProductColourAndSize colourSize = (ProductColourAndSize)product.getColourSizes().iterator().next(); ProductBarcode barcode = new ProductBarcode("498765123452", colourSize, barcodeType); colourSize.addBarcode(barcode); // the "magic" line that makes all the difference... // colourSize.getBarcodes().size(); // save the product again... DataAccessService.saveOrUpdate(session, product); // test whether there is only one barcode in the collection (which there should be) assertTrue("barcodes.size() should == 1 but was actually " + colourSize.getBarcodes().size(), colourSize.getBarcodes().size() == 1); } catch (Exception e) { log.fatal("?", e); fail("exception"); } finally { if (product != null) { try { Iterator colourSizeIterator = product.getColourSizes().iterator(); while (colourSizeIterator.hasNext()) { ProductColourAndSize deleteMe = (ProductColourAndSize)colourSizeIterator.next(); colourSizeIterator.remove(); DataAccessService.delete(session, deleteMe); } DataAccessService.saveOrUpdate(session, product); } catch (Exception e) { log.warn("couldn't remove colours/sizes and resave product", e); } try { DataAccessService.delete(session, product); } catch (Exception e2) { log.error("cleanup failed: could not delete unittest product " + product.getProductID(), e2); } } } } catch (Exception e) { log.error("?", e); fail("exception"); } finally { if (session != null && session.isOpen()) { session.close(); } } } } } --------------------------------------------------------------------- JIRA INFORMATION: This message is automatically generated by JIRA. If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa If you want more information on JIRA, or have a bug to report see: http://www.atlassian.com/software/jira |