You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2006/07/15 16:49:28 UTC
svn commit: r422240 [2/2] - in /db/ojb/trunk/src/test/org/apache/ojb:
broker/ broker/sequence/ broker/sqlcount/ compare/ junit/ odmg/
Modified: db/ojb/trunk/src/test/org/apache/ojb/odmg/CircularTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/odmg/CircularTest.java?rev=422240&r1=422239&r2=422240&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/odmg/CircularTest.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/odmg/CircularTest.java Sat Jul 15 07:49:27 2006
@@ -1,16 +1,6 @@
package org.apache.ojb.odmg;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
-import org.apache.ojb.junit.ODMGTestCase;
-import org.odmg.OQLQuery;
-import org.odmg.Transaction;
-
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +15,19 @@
* limitations under the License.
*/
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.Identity;
+import org.apache.ojb.junit.ODMGTestCase;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.odmg.OQLQuery;
+import org.odmg.Transaction;
+
/**
* Testing complex object graphs with circular and bidirectional references when
* using database foreign key settings (without support of deferred foreign keys).
@@ -41,7 +44,7 @@
* - Shop has a FK to ShopDetail<br/>
* - Product has a FK to Product<br/>
* - Product has a FK to Shop<br/>
- * - CT_SHOP_DISTRIBUTOR indirection table has FK's to Shop and Distributor<br/>
+ * - CT_SHOP_DIST indirection table has FK's to Shop and Distributor<br/>
* <p/>
* Here a summery of the dependencies:<br/>
* Shop--1:1-->ShopDetail--1:1-->Shop<br/>
@@ -74,6 +77,163 @@
}
/**
+ * Test for OJB-103
+ *
+ * Reproduce issue posted by user:
+ * Consider A1 and B1 cross referenced objetcs, each one referring the other.
+ The process consists with create A2, and replace A1.
+ So, with ODMG, we wrote something like that :
+ 1. retrieve A1, retrieve B1 with A1.getB()
+ 2. instanciation and lock of A2
+ 3. A2.setB(B1)
+ 4. delete A1 (markDelete)
+ 5. lock B1, B1.setA(null)
+ 6. flush (assume it is required)
+ 7. lock B1
+ 8. B1.setA(A2)
+ 9. commit
+ After commit, we observed that in database, B1 doesn't refers A2 !!
+ */
+ public void testBidirectionalOneToOneMoveObject_2()
+ {
+ String name = "testBidirectionalOneToOneMoveObject_2_" + System.currentTimeMillis();
+ Shop s1_new = new Shop(name + "_1");
+ ShopDetail sd_new = new ShopDetail(name + "_1");
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ // insert new objects
+ database.makePersistent(sd_new);
+ database.makePersistent(s1_new);
+ tx.flush();
+ s1_new.setDetail(sd_new);
+ sd_new.setShop(s1_new);
+ tx.commit();
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1_new);
+ Shop s1 = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ // check bidirectional reference
+ assertNotNull(s1);
+ assertNotNull(s1.getDetail());
+
+ tx = (TransactionExt) odmg.newTransaction();
+ // use implicit locking
+ tx.setImplicitLocking(true);
+ tx.begin();
+ // get the object to move
+ ShopDetail sd = s1.getDetail();
+ // create new Shop
+ Shop s2 = new Shop(name + "_2");
+ tx.lock(s2, Transaction.WRITE);
+ //sd.setShop(null);
+ s2.setDetail(sd);
+ database.deletePersistent(s1);
+ tx.lock(sd, Transaction.WRITE);
+ sd.setShop(null);
+ tx.flush();
+ tx.lock(sd, Transaction.WRITE);
+ sd.setShop(s2);
+ tx.commit();
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ s1 = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNull(s1);
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid_2 = tx.getBroker().serviceIdentity().buildIdentity(s2);
+ Shop s2_ = (Shop) tx.getBroker().getObjectByIdentity(oid_2);
+ tx.commit();
+ // check bidirectional reference
+ assertNotNull(s2_);
+ assertNotNull(s2_.getDetail());
+ assertEquals(sd_new.getId(), s2_.getDetail().getId());
+ assertNotNull(s2_.getDetail().getShop());
+ assertEquals(s2_, s2_.getDetail().getShop());
+ }
+
+ /**
+ * Reproduce issue posted by user:
+ * Consider A1 and B1 cross referenced objetcs, each one referring the other.
+ The process consists with create A2, and replace A1.
+ So, with ODMG, we wrote something like that :
+ 1. retrieve A1, retrieve B1 with A1.getB()
+ 2. instanciation and lock of A2
+ 3. A2.setB(B1)
+ 4. delete A1 (markDelete)
+ 5. lock B1, B1.setA(null)
+ 6. flush (assume it is required)
+ 7. lock B1
+ 8. B1.setA(A2)
+ 9. commit
+ After commit, we observed that in database, B1 doesn't refers A2 !!
+ */
+ public void testBidirectionalOneToOneMoveObject()
+ {
+ String name = "testBidirectionalOneToOneMoveObject_" + System.currentTimeMillis();
+ Shop s1_new = new Shop(name + "_1");
+ ShopDetail sd_new = new ShopDetail(name + "_1");
+
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ // insert new objects
+ database.makePersistent(sd_new);
+ database.makePersistent(s1_new);
+ tx.flush();
+ s1_new.setDetail(sd_new);
+ sd_new.setShop(s1_new);
+ tx.commit();
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1_new);
+ Shop s1 = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ // check bidirectional reference
+ assertNotNull(s1);
+ assertNotNull(s1.getDetail());
+
+ tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ // to make this test more transparent disable implicit locking
+ tx.setImplicitLocking(false);
+ // get the object to move
+ ShopDetail sd = s1.getDetail();
+ // create new Shop
+ Shop s2 = new Shop(name + "_2");
+ // now lock all relevant objects
+ tx.lock(s2, Transaction.WRITE);
+ tx.lock(s1, Transaction.WRITE);
+ tx.lock(sd, Transaction.WRITE);
+ s2.setDetail(sd);
+ sd.setShop(s2);
+ s1.setDetail(null);
+ database.deletePersistent(s1);
+ tx.commit();
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ s1 = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNull(s1);
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid_2 = tx.getBroker().serviceIdentity().buildIdentity(s2);
+ Shop s2_ = (Shop) tx.getBroker().getObjectByIdentity(oid_2);
+ tx.commit();
+ // check bidirectional reference
+ assertNotNull(s2_);
+ assertNotNull(s2_.getDetail());
+ assertEquals(sd_new.getId(), s2_.getDetail().getId());
+ assertNotNull(s2_.getDetail().getShop());
+ assertEquals(s2_, s2_.getDetail().getShop());
+ }
+
+ /**
* Handling circular 1:n references with FK settings and use of
* auto-delete setting to delete object graph.
*/
@@ -90,25 +250,25 @@
tx.begin();
p1.addSubProduct(p2);
p2.addSubProduct(p3);
- database.makePersistent(p1);
+ database.makePersistent(p3);
// before establishing the circular references write
// all objects to DB
tx.flush();
// now close the circular references
- p2.addSubProduct(p1);
+ p3.addSubProduct(p1);
tx.commit();
tx.begin();
// on delete break the circular references first, then delete the
// start object
- tx.lock(p2, Transaction.WRITE);
+ tx.lock(p3, Transaction.WRITE);
+ // this call is only needed if auto-delete setting in repository is 'object'
tx.setCascadingDelete(Product.class, "subProducts", false);
- p2.setSubProducts(null);
+ p3.setSubProducts(null);
tx.flush();
- tx.setCascadingDelete(Product.class, "subProducts", true);
- database.deletePersistent(p1);
- // this object was unlinked on fluhs(), so we have to remove it by hand
database.deletePersistent(p3);
+ database.deletePersistent(p2);
+ database.deletePersistent(p1);
tx.commit();
tx.begin();
@@ -180,6 +340,55 @@
}
/**
+ * Handling circular 1:n references with FK settings and use of
+ * auto-delete setting to delete object graph.
+ */
+ public void testCircularOneToN_3() throws Exception
+ {
+ String name = "testCircularOneToN_3_" + System.currentTimeMillis();
+ ojbChangeReferenceSetting(Product.class, "subProducts", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
+
+ Product p1 = new Product(name + "_p1");
+ Product p2 = new Product(name + "_p2");
+ Product p3 = new Product(name + "_p3");
+
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ p1.addSubProduct(p2);
+ p2.addSubProduct(p3);
+ database.makePersistent(p3);
+ // before establishing the circular references write
+ // all objects to DB
+ tx.flush();
+ // now close the circular references
+ p3.addSubProduct(p1);
+ tx.commit();
+
+ tx.begin();
+ // on delete break the circular references first, then delete the
+ // start object
+ tx.lock(p3, Transaction.WRITE);
+ // this call is only needed if auto-delete setting in repository is 'object'
+ tx.setCascadingDelete(Product.class, "subProducts", false);
+ p3.setSubProducts(null);
+ tx.flush();
+ // this call is only needed if auto-delete setting in repository is 'none'
+ // to enable cascade delete, else we have to delete each object by hand
+ tx.setCascadingDelete(Product.class, "subProducts", true);
+ database.deletePersistent(p1);
+ tx.commit();
+
+ tx.begin();
+ OQLQuery query = odmg.newOQLQuery();
+ query.create("select objects from " + Product.class.getName() + " where name like $1");
+ query.bind(name + "%");
+ Collection result = (Collection) query.execute();
+ tx.commit();
+
+ assertEquals(0, result.size());
+ }
+
+ /**
* Use auto-delete setting to delete object graph.
*/
public void testCircularWithAutoDeleteEnabled() throws Exception
@@ -355,30 +564,76 @@
}
/**
- * Test show handling with circular references and database FK settings.
+ * Handle circuler 1:1 with default methods.
*/
- public void testBidirectionalWithConstraint_1a() throws Exception
+ public void testBidirectionalWithConstraint() throws Exception
{
- String name = "testBidirectionalWithConstraint_1a_" + System.currentTimeMillis();
+ String name = "testBidirectionalWithConstraint_" + System.currentTimeMillis();
+
+ Shop s1 = new Shop(name + "_1");
+ ShopDetail sd = new ShopDetail(name + "_1");
+
TransactionExt tx = (TransactionExt) odmg.newTransaction();
tx.begin();
+ database.makePersistent(sd);
+ database.makePersistent(s1);
+ tx.flush();
+ s1.setDetail(sd);
+ sd.setShop(s1);
+ tx.commit();
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
+
+
+ tx.begin();
+ database.deletePersistent(s1);
+ tx.flush();
+ database.deletePersistent(sd);
+ tx.commit();
+ }
+
+ /**
+ * Handle circuler 1:1 with default methods.
+ */
+ public void testBidirectionalWithConstraint_1a() throws Exception
+ {
+ String name = "testBidirectionalWithConstraint_1a_" + System.currentTimeMillis();
Shop s1 = new Shop(name + "_1");
ShopDetail sd = new ShopDetail(name + "_1");
s1.setDetail(sd);
sd.setShop(s1);
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ database.makePersistent(sd);
+ tx.flush();
database.makePersistent(s1);
tx.commit();
tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
+
+ tx.begin();
database.deletePersistent(s1);
+ tx.flush();
database.deletePersistent(sd);
tx.commit();
}
/**
- * If the user take care of the ordering itself the test pass.
+ * Define order of object operations using flush() method.
*/
public void testBidirectionalWithConstraint_1b() throws Exception
{
@@ -403,9 +658,19 @@
tx.commit();
tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
+
+ tx.begin();
// madatory to mark object with DB FK constraint first on delete
- // then OJB will use this order to delete the bidirectional objects
+ // (FK from Shop to ShopDetail) then OJB will use this order to
+ // delete the bidirectional objects
database.deletePersistent(s1);
+ tx.flush();
database.deletePersistent(sd);
tx.commit();
}
@@ -416,22 +681,39 @@
public void testBidirectionalWithConstraint_1c() throws Exception
{
String name = "testBidirectionalWithConstraint_1c_" + System.currentTimeMillis();
- TransactionExt tx = (TransactionExt) odmg.newTransaction();
- tx.begin();
Shop s1 = new Shop(name + "_1");
ShopDetail sd = new ShopDetail(name + "_1");
s1.setDetail(sd);
sd.setShop(s1);
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ // set implicit locking false to determine order of objects
+ tx.setImplicitLocking(false);
+ // to prevent reordering of object, disable ordering
+ // in many cases this is not needed, because OJB will leave ordering
+ // tx.setOrdering(false);
+ tx.begin();
// madatory to persist referenced ShopDetail first, the Shop
// object will be detected automatic. In this case first the ShopDetail
// will be created and then the Shop
database.makePersistent(sd);
database.makePersistent(s1);
+ // now write objects to database
+ tx.flush();
+ // this call will now detect the changed FK values of the bidirectional 1:1 reference
tx.commit();
tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
+
+ // we using the same tx, thus locking and (ordering) is still disabled
+ tx.begin();
// madatory to mark object with DB FK constraint first on delete
// then OJB will use this order to delete the bidirectional objects
database.deletePersistent(s1);
@@ -461,8 +743,17 @@
// only for testing, we completely bypass odmg
tx.getBroker().beginTransaction();
tx.getBroker().store(s1);
+ // we need this call to assign the Shop FK in ShopDetail
+ tx.getBroker().store(sd);
tx.commit();
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
tx.begin();
// only for testing, we completely bypass odmg
@@ -474,6 +765,63 @@
}
/**
+ * Handle circular 1:1 by using a 'constraint'-flag property in
+ * reference-descriptor to make OJB's ordering algorithm more
+ * sophisticated.
+ */
+ public void testBidirectionalWithConstraint_1e() throws Exception
+ {
+ String name = "testBidirectionalWithConstraint_1e_" + System.currentTimeMillis();
+ ObjectReferenceDescriptor ord = null;
+
+ try
+ {
+ CircularTest.Shop s1 = new CircularTest.Shop(name + "_1");
+ CircularTest.ShopDetail sd = new CircularTest.ShopDetail(name + "_1");
+ s1.setDetail(sd);
+ sd.setShop(s1);
+
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ tx.begin();
+ // now we tell OJB that one 1:1 reference of the bidirectional 1:1 reference
+ // between Shop and ShopDetail has a FK constraint
+ ClassDescriptor cld = tx.getBroker().getClassDescriptor(CircularTest.Shop.class);
+ ord = cld.getObjectReferenceDescriptorByName("detail");
+ // current DB schema create a foreign key constraint and we can
+ // inform OJB
+ ord.setConstraint(true);
+ // now it doesn't matter in which order we persist the new objects, OJB should
+ // always reorder the objects before insert/update call
+ database.makePersistent(sd);
+ // or
+ // database.makePersistent(s1);
+ tx.commit();
+
+ tx.begin();
+ tx.getBroker().clearCache();
+ Identity oid = tx.getBroker().serviceIdentity().buildIdentity(s1);
+ Shop newShop = (Shop) tx.getBroker().getObjectByIdentity(oid);
+ tx.commit();
+ assertNotNull(newShop);
+ assertNotNull(newShop.getDetail());
+
+ tx.begin();
+ // with cascading delete and the declared FK constraint OJB
+ // always use the correct order on delete.
+ tx.setCascadingDelete(CircularTest.ShopDetail.class, true);
+ database.deletePersistent(sd);
+ // or
+ // database.deletePersistent(s1);
+ tx.commit();
+ }
+ finally
+ {
+ // restore old setting
+ if(ord != null) ord.setConstraint(false);
+ }
+ }
+
+ /**
* Test show handling with circular references and database FK settings.
*/
public void testCircularOneToOne_1a() throws Exception
@@ -604,100 +952,10 @@
}
/**
- * This test fails!! The ordering isn't able to handle this without causing
- * a key constraint violation.
- */
- public void testCircularOneToOne_1c() throws Exception
- {
- String name = "testCircularOneToOne_1c_" + System.currentTimeMillis();
-
- TransactionExt tx = (TransactionExt) odmg.newTransaction();
- tx.begin();
-
- ObjectA a = new ObjectA(name + "_ObjectA");
- ObjectAA aa = new ObjectAA(name + "_ObjectAA");
- ObjectAAA aaa = new ObjectAAA(name + "_ObjectAAA");
- ObjectAAAA aaaa = new ObjectAAAA(name + "_ObjectAAAA");
- // now set the circular references
- a.setRefAA(aa);
- aa.setRefAAA(aaa);
- aaa.setRefAAAA(aaaa);
- aaaa.setRefA(a);
- // use any object to store the whole graph
- //database.makePersistent(aaaa);
- //database.makePersistent(aaa);
- database.makePersistent(aaa);
- //database.makePersistent(a);
- tx.commit();
-
- tx.begin();
- OQLQuery query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectA.class.getName() + " where name like $1");
- query.bind(name + "%");
- Collection result = (Collection) query.execute();
- assertEquals(1, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(1, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(1, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAAAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(1, result.size());
- tx.commit();
-
- tx.begin();
- // we force OJB to respect user order
- tx.setNoteUserOrder(true);
- // we specify the objects to delete in the correct order
- database.deletePersistent(a);
- database.deletePersistent(aa);
- database.deletePersistent(aaa);
- database.deletePersistent(aaaa);
- tx.commit();
-
- tx.begin();
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(0, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(0, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(0, result.size());
-
- query = odmg.newOQLQuery();
- query.create("select objects from " + ObjectAAAA.class.getName() + " where name like $1");
- query.bind(name + "%");
- result = (Collection) query.execute();
- assertEquals(0, result.size());
- tx.commit();
- }
-
- /**
* Do manually ordering using {@link TransactionExt#setOrdering(boolean)} to disable
* OJB's ordering algorithm (and implicit locking).
*/
- public void testCircularOneToOne_1d() throws Exception
+ public void testCircularOneToOne_1c() throws Exception
{
String name = "testCircularOneToOne_1d_" + System.currentTimeMillis();
@@ -720,7 +978,7 @@
*/
tx.setOrdering(false);
tx.setImplicitLocking(false);
-
+
database.makePersistent(aaaa);
database.makePersistent(aaa);
database.makePersistent(aa);
@@ -755,7 +1013,7 @@
tx.begin();
/*
- the ordering/implicit locking of the tx is still disabled,
+ the ordering/implicit locking of the tx is still disabled (tx instance hasn't changed),
so we have to take care of correct order of objects while deletion
*/
database.deletePersistent(a);
@@ -814,9 +1072,8 @@
/*
we manually determine the insert object order
*/
- tx.setOrdering(true);
- tx.setImplicitLocking(true);
- tx.setNoteUserOrder(true);
+ tx.setOrdering(false);
+ tx.setImplicitLocking(false);
database.makePersistent(aaaa);
database.makePersistent(aaa);
@@ -916,15 +1173,12 @@
}
/**
- * If the user take care of the ordering itself the test pass.
+ * User take care of the ordering itself.
*/
public void testCircularOneToOne_2a() throws Exception
{
String name = "testCircularOneToOne_2_" + System.currentTimeMillis();
- TransactionExt tx = (TransactionExt) odmg.newTransaction();
- tx.begin();
-
ObjectA a = new ObjectA(name + "_ObjectA");
ObjectAA aa = new ObjectAA(name + "_ObjectAA");
ObjectAAA aaa = new ObjectAAA(name + "_ObjectAAA");
@@ -932,11 +1186,20 @@
a.setRefAA(aa);
aa.setRefAAA(aaa);
aaa.setRefA(a);
+
+ TransactionExt tx = (TransactionExt) odmg.newTransaction();
+ // we want control object insert order itself, thus
+ // disable implicite locking and ordering
+ tx.setImplicitLocking(false);
+ tx.setOrdering(false);
+ tx.begin();
database.makePersistent(aaa);
database.makePersistent(aa);
database.makePersistent(a);
tx.commit();
+ // we use the same tx again, thus implicite locking
+ // and ordering is still disabled
tx.begin();
database.deletePersistent(a);
database.deletePersistent(aa);
@@ -1113,11 +1376,9 @@
}
/**
- * Class Shop has a bidirectional 1:1 reference with ShopDetail and the DB table of Shop
- * has a foreign key constraint on ShopDetail table. Shop has a m:n relation with Distributor.
- * <p/>
- * This test fails!! The ordering isn't able to handle this with causing
- * a key constraint violation.
+ * Class Shop has a bidirectional 1:1 reference with ShopDetail
+ * (FK constraint from SHOP to SHOP_DETAIL table).
+ * Shop has a m:n relation with Distributor.
*/
public void testBidirectionalWithConstraint_2a() throws Exception
{
@@ -1140,6 +1401,8 @@
// touch the Distributor object
tx.begin();
database.deletePersistent(s1);
+ // flush to avoid constraint error
+ tx.flush();
database.deletePersistent(sd);
tx.commit();
}
@@ -1152,62 +1415,30 @@
*/
public void testBidirectionalWithConstraint_2b() throws Exception
{
- String name = "testBidirectionalWithConstraint_2b_" + System.currentTimeMillis();
+ String name = "testBidirectionalWithConstraint_2c_" + System.currentTimeMillis();
Shop s1 = new Shop(name + "_1");
- ShopDetail sd = new ShopDetail(name + "_1");
- s1.setDetail(sd);
- sd.setShop(s1);
Distributor d1 = new Distributor(name + "_1");
s1.addDistributor(d1);
d1.addShop(s1);
TransactionExt tx = (TransactionExt) odmg.newTransaction();
tx.begin();
- // mandatory to first persist the referenced object of the
- // bidirectional 1:1 reference, because of the FK in Shop
- // the m:n relation will be handled without problems
- database.makePersistent(sd);
- // it's not needed to declare all objects in this case,
- // but it wouldn't affect
- // database.makePersistent(s1);
- // database.makePersistent(d1);
- tx.commit();
-
- // Now we delete the Shop with ShopDetail, but don't
- // touch the Distributor object
- tx.begin();
- database.deletePersistent(s1);
- database.deletePersistent(sd);
- tx.commit();
- }
-
- /**
- * Class Shop has a bidirectional 1:1 reference with ShopDetail and the DB table of Shop
- * has a foreign key constraint on ShopDetail table. Shop has a m:n relation with Distributor.
- * <p/>
- * If the user take care of the ordering itself the test pass.
- */
- public void testBidirectionalWithConstraint_2c() throws Exception
- {
- String name = "testBidirectionalWithConstraint_2c_" + System.currentTimeMillis();
- TransactionExt tx = (TransactionExt) odmg.newTransaction();
- tx.begin();
- // When using flush() we can use a more "natural" object persisting order
- Shop s1 = new Shop(name + "_1");
- Distributor d1 = new Distributor(name + "_1");
- s1.addDistributor(d1);
- d1.addShop(s1);
+ // When using flush() we can add objects step by step
database.makePersistent(s1);
tx.flush();
+ // add the shop detail object to Shop
ShopDetail sd = new ShopDetail(name + "_1");
s1.setDetail(sd);
sd.setShop(s1);
tx.commit();
- // Delete all created objects
+ // Delete all created objects, we disable implicit
+ // locking and ordering to avoid constraint error
+ tx.setImplicitLocking(false);
+ tx.setOrdering(false);
tx.begin();
database.deletePersistent(d1);
database.deletePersistent(s1);
@@ -1414,7 +1645,7 @@
tx.getBroker().clearCache();
OQLQuery query = odmg.newOQLQuery();
- query.create("select products from " + Shop.class.getName() + " where name like $1");
+ query.create("select shops from " + Shop.class.getName() + " where name like $1");
query.bind(name + "%");
Collection result = (Collection) query.execute();
tx.commit();
@@ -1428,6 +1659,8 @@
for(Iterator iterator = newShop.getProducts().iterator(); iterator.hasNext();)
{
Product p = (Product) iterator.next();
+ assertNotNull(p.getShop());
+ assertEquals(s.getId(), p.getShop().getId());
if(p.getSubProducts() != null && p.getSubProducts().size() > 0)
{
match = true;
@@ -1659,6 +1892,10 @@
TransactionExt tx = (TransactionExt) odmg.newTransaction();
tx.begin();
database.makePersistent(s);
+ // before establishing the circular references write
+ // all objects to DB
+ tx.flush();
+ // now close the circular references
tx.commit();
tx.begin();
@@ -1714,12 +1951,11 @@
sd.setName(name);
s.setDetail(sd);
sd.setShop(s);
+
TransactionExt tx = (TransactionExt) odmg.newTransaction();
tx.begin();
- database.makePersistent(sd);
database.makePersistent(s);
database.deletePersistent(s);
- database.makePersistent(sd);
database.makePersistent(s);
tx.commit();
@@ -1735,24 +1971,28 @@
assertNotNull(newShop.getDetail());
tx.begin();
- // We enable cascading delete for all references of Shop class
- tx.setCascadingDelete(Shop.class, true);
database.deletePersistent(newShop);
+ // add object again, we expect that nothing was deleted
database.makePersistent(newShop);
+ // flush changes to DB, we don't change anything
tx.flush();
-
query = odmg.newOQLQuery();
query.create("select shops from " + Shop.class.getName() + " where name like $1");
query.bind(name);
result = (Collection) query.execute();
tx.commit();
+
assertEquals(1, result.size());
+ Shop tmp = (Shop) result.iterator().next();
+ assertNotNull(tmp.getDetail());
tx.begin();
database.deletePersistent(newShop);
database.makePersistent(newShop);
database.deletePersistent(newShop);
tx.flush();
+ database.deletePersistent(newShop.getDetail());
+ tx.flush();
query = odmg.newOQLQuery();
query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
@@ -1794,8 +2034,12 @@
TransactionExt tx = (TransactionExt) odmg.newTransaction();
tx.begin();
- database.makePersistent(sd);
database.makePersistent(s);
+ // shop and shopDetail have a bidirectional 1:1 reference
+ // on flush() OJB will insert both objects and set one FK
+ tx.flush();
+ // on commit() OJB will be aware of the bidirectional reference
+ // and set the second FK
tx.commit();
tx.begin();
@@ -1812,9 +2056,8 @@
assertNotNull(sdNew.getShop());
tx.begin();
- // cascading delete should not affect Shop deletion
+ // cascading delete should delete Shop too
tx.setCascadingDelete(ShopDetail.class, true);
- database.deletePersistent(sdNew.getShop());
database.deletePersistent(sdNew);
tx.flush();
@@ -1909,6 +2152,19 @@
}
this.distributors.add(d);
}
+
+ public boolean equals(Object obj)
+ {
+ if(obj instanceof Shop)
+ {
+ Shop tmp = (Shop) obj;
+ return new EqualsBuilder().append(id, tmp.id).append(name, tmp.name).isEquals();
+ }
+ else
+ {
+ return this == obj;
+ }
+ }
}
public static class Distributor
@@ -2098,9 +2354,22 @@
{
this.shop = shop;
}
+
+ public boolean equals(Object obj)
+ {
+ if(obj instanceof ShopDetail)
+ {
+ ShopDetail tmp = (ShopDetail) obj;
+ return new EqualsBuilder().append(id, tmp.id).append(name, tmp.name).isEquals();
+ }
+ else
+ {
+ return this == obj;
+ }
+ }
}
- abstract static class BaseObject
+ public abstract static class BaseObject
{
private Integer id;
private String name;
Modified: db/ojb/trunk/src/test/org/apache/ojb/odmg/CollectionsTest.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/test/org/apache/ojb/odmg/CollectionsTest.java?rev=422240&r1=422239&r2=422240&view=diff
==============================================================================
--- db/ojb/trunk/src/test/org/apache/ojb/odmg/CollectionsTest.java (original)
+++ db/ojb/trunk/src/test/org/apache/ojb/odmg/CollectionsTest.java Sat Jul 15 07:49:27 2006
@@ -8,22 +8,24 @@
import java.util.List;
import java.util.Vector;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerFactory;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.core.proxy.CollectionProxy;
import org.apache.ojb.broker.metadata.CollectionDescriptor;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.QueryFactory;
import org.apache.ojb.junit.ODMGTestCase;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
import org.odmg.OQLQuery;
import org.odmg.Transaction;
/**
* Test case handles with collections.
*
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
* @version $Id$
*/
public class CollectionsTest extends ODMGTestCase
@@ -49,6 +51,138 @@
super.tearDown();
}
+ private PersistenceBrokerInternal getInternalPB(TransactionExt tx)
+ {
+ return (PersistenceBrokerInternal) tx.getBroker();
+ }
+
+ public void testProxiedReferences() throws Exception
+ {
+ ojbChangeReferenceSetting(Gatherer.class, "collectiblesA", true,
+ CollectionDescriptor.CASCADE_NONE, CollectionDescriptor.CASCADE_OBJECT, true);
+
+ String prefix = "testProxiedReferences_" + System.currentTimeMillis();
+ String queryId = "select gatherer from " + Gatherer.class.getName() + " where gatId=$1";
+ String queryName = "select gatherer from " + Gatherer.class.getName() + " where name=$1";
+
+ // prepare test case
+ Gatherer gat = new Gatherer(null, prefix + "_Gatherer");
+ CollectibleA[] cols = prepareCollectibleA(gat, prefix);
+ List colList = Arrays.asList(cols);
+ // set List of CollectiblesA objects
+ gat.setCollectiblesA(colList);
+ TransactionExt tx = (TransactionExt)odmg.newTransaction();
+ tx.begin();
+ database.makePersistent(gat);
+ tx.commit();
+
+ // check if gatherer was stored
+ tx.begin();
+ // to run this test with all cache implementation classes
+ // clear the cache before query
+ tx.getBroker().clearCache();
+ OQLQuery query = odmg.newOQLQuery();
+ query.create(queryId);
+ Integer gatId = gat.getGatId();
+ assertNotNull(gatId);
+ query.bind(gatId);
+ Collection result = (Collection) query.execute();
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ Gatherer newGat = (Gatherer) result.iterator().next();
+ assertTrue(getInternalPB(tx).getProxyFactory().isCollectionProxy(newGat.getCollectiblesA()));
+ CollectionProxy cp = getInternalPB(tx).getProxyFactory().getCollectionProxy(newGat.getCollectiblesA());
+ assertFalse(cp.isLoaded());
+ tx.commit();
+
+ tx.begin();
+ query = odmg.newOQLQuery();
+ query.create(queryName);
+ query.bind(gat.getName());
+ result = (Collection) query.execute();
+ assertNotNull(result);
+ assertEquals(1, result.size());
+ newGat = (Gatherer) result.iterator().next();
+ assertTrue(getInternalPB(tx).getProxyFactory().isCollectionProxy(newGat.getCollectiblesA()));
+ cp = getInternalPB(tx).getProxyFactory().getCollectionProxy(newGat.getCollectiblesA());
+ assertFalse(cp.isLoaded());
+ tx.commit();
+
+ tx.begin();
+ PersistenceBroker pb = tx.getBroker();
+ Identity oid = pb.serviceIdentity().buildIdentity(Gatherer.class, gat.getGatId());
+ newGat = (Gatherer) pb.getObjectByIdentity(oid);
+ assertNotNull(newGat);
+ assertTrue(getInternalPB(tx).getProxyFactory().isCollectionProxy(newGat.getCollectiblesA()));
+ cp = getInternalPB(tx).getProxyFactory().getCollectionProxy(newGat.getCollectiblesA());
+ assertFalse(cp.isLoaded());
+ tx.commit();
+ }
+
+ /**
+ * tests behavior of 1:n references in OJB (odmg-api) when auto-retrieve is disabled.
+ * @throws Exception
+ */
+ public void testSetAutoRetrieveFalse() throws Exception
+ {
+ ojbChangeReferenceSetting(Gatherer.class, "collectiblesA", false,
+ CollectionDescriptor.CASCADE_NONE, CollectionDescriptor.CASCADE_OBJECT, true);
+ ojbChangeReferenceSetting(Gatherer.class, "collectiblesC", false,
+ CollectionDescriptor.CASCADE_NONE, CollectionDescriptor.CASCADE_OBJECT, true);
+
+ String prefix = "testSetAutoRetrieveFalse_" + System.currentTimeMillis();
+
+ // prepare test case
+ Gatherer gat = new Gatherer(null, prefix + "_Gatherer");
+ CollectibleA[] cols = prepareCollectibleA(gat, prefix);
+ List colList = Arrays.asList(cols);
+ // set List of CollectiblesA objects
+ gat.setCollectiblesA(colList);
+ TransactionExt tx = (TransactionExt)odmg.newTransaction();
+ tx.begin();
+ database.makePersistent(gat);
+ tx.commit();
+
+ tx.begin();
+ PersistenceBroker pb = tx.getBroker();
+ pb.clearCache();
+ Identity oid = pb.serviceIdentity().buildIdentity(Gatherer.class, gat.getGatId());
+ Gatherer newGat = (Gatherer) pb.getObjectByIdentity(oid);
+ tx.commit();
+
+ tx.begin();
+ tx.lock(newGat, Transaction.WRITE);
+ newGat.setName(prefix + "_updated");
+ //tx.getBroker().retrieveAllReferences(newGat);
+ tx.commit();
+
+ tx.begin();
+ pb = tx.getBroker();
+ newGat = (Gatherer) pb.getObjectByIdentity(oid);
+ pb.retrieveAllReferences(newGat);
+ assertEquals(cols.length, newGat.getCollectiblesA().size());
+ tx.commit();
+
+ tx.begin();
+ pb = tx.getBroker();
+ pb.clearCache();
+ newGat = (Gatherer) pb.getObjectByIdentity(oid);
+ tx.commit();
+
+ tx.begin();
+ tx.lock(newGat, Transaction.WRITE);
+ newGat.addCollectibleA(new CollectibleA(prefix + "_later_added"));
+ tx.commit();
+
+ tx.begin();
+ pb = tx.getBroker();
+ newGat = (Gatherer) pb.getObjectByIdentity(oid);
+ pb.retrieveAllReferences(newGat);
+ tx.commit();
+ assertNotNull(newGat);
+ assertEquals(cols.length + 1, newGat.getCollectiblesA().size());
+
+ }
public void testStoreDeleteCascadeDelete() throws Exception
{
@@ -475,8 +609,8 @@
// we want automatic delete of removed collection objects
//tx.autoDeleteRemovedCollectionReferences(true);
// alternative do explicit call Database#deletePersistent for removed objects
- // fetchedGat.getCollectiblesA().remove(0)
- // fetchedGat.getCollectiblesB().remove(0);
+ fetchedGat.getCollectiblesA().remove(0);
+ fetchedGat.getCollectiblesB().remove(0);
tx.getBroker().serviceObjectCache().cache(tx.getBroker().serviceIdentity().buildIdentity(fetchedGat), fetchedGat);
//System.out.println("remove: " + tx.getBroker().serviceIdentity().buildIdentity(fetchedGat.getCollectiblesA().remove(0)));
//System.out.println("remove: " + tx.getBroker().serviceIdentity().buildIdentity(fetchedGat.getCollectiblesB().remove(0)));
@@ -538,7 +672,7 @@
tx.commit();
tx.begin();
- ((TransactionExt)tx).getBroker().clearCache();
+ tx.getBroker().clearCache();
OQLQuery query = odmg.newOQLQuery();
query.create(queryStr);
query.bind(name);
@@ -558,7 +692,7 @@
tx.commit();
tx.begin();
- ((TransactionExt)tx).getBroker().clearCache();
+ tx.getBroker().clearCache();
query = odmg.newOQLQuery();
query.create(queryStr);
query.bind(name);
@@ -581,7 +715,7 @@
tx.commit();
tx.begin();
- ((TransactionExt)tx).getBroker().clearCache();
+ tx.getBroker().clearCache();
query = odmg.newOQLQuery();
query.create(queryStr);
query.bind(name);
@@ -1169,9 +1303,9 @@
{
private Integer gatId;
private String name;
- private List collectiblesA = new Vector();
- private List collectiblesB = new Vector();
- private List collectiblesC = new Vector();
+ private List collectiblesA = new ArrayList();
+ private List collectiblesB = new ArrayList();
+ private List collectiblesC = new ArrayList();
public Gatherer()
{
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org