Package org.apache.ojb.odmg

Source Code of org.apache.ojb.odmg.CircularTest$ObjectAAAA

package org.apache.ojb.odmg;

/* 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.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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.junit.ODMGTestCase;
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).
* <p/>
* The classes hierarchy looks like:
* <br/>
* Class Shop has a bidirectional 1:1 reference with ShopDetail.<br/>
* Shop has a 1:n relation with Product, Product has a 1:1 reference to Shop.<br/>
* Shop has a m:n relation with Distributor.<br/>
* Product has a 1:n relation to itself to handle sub-Products.<br/>
* <p/>
* In the database the following foreign keys are declared:
* <br/>
* - 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/>
* <p/>
* Here a summery of the dependencies:<br/>
* Shop--1:1-->ShopDetail--1:1-->Shop<br/>
* Shop--1:n-->Product--1:1-->Shop<br/>
* Product--1:n-->Product<br/>
* Shop--m:n-->Distributor<br/>
* <p/>
* <p/>
* Class ObjectA has a 1:1 reference to ObjectAA,<br/>
* ObjectAA has 1:1 to ObjectAAA,<br/>
* ObjectAAA has 1:1 to ObjectA and to ObjectAAAA,<br/>
* ObjectAAAA has 1:1 to ObjectA<br/>
* <br/>
* - ObjectA has FK to ObjectAA<br/>
* - ObjectAA has FK to ObjectAAA<br/>
* - ObjectAAA has FK to ObjectAAAA<br/>
* <p/>
* Here a summery of the dependencies:<br/>
* ObjetA--1:1-->ObjectAA--1:1-->ObjectAAA--1:1-->ObjectA
* ObjetA--1:1-->ObjectAA--1:1-->ObjectAAA--1:1-->ObjectAAAA--1:1-->ObjectA
*
* @version $Id: CircularTest.java,v 1.1.2.10 2005/12/21 22:31:28 tomdz Exp $
*/
public class CircularTest extends ODMGTestCase
{
    public static void main(String[] args)
    {
        String[] arr = {CircularTest.class.getName()};
        junit.textui.TestRunner.main(arr);
    }

    /**
     * Handling circular 1:n references with FK settings and use of
     * auto-delete setting to delete object graph.
     */
    public void testCircularOneToN_1() throws Exception
    {
        String name = "testCircularOneToN_1_" + 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();
        database.deletePersistent(p3);
        database.deletePersistent(p2);
        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());
    }

    /**
     * Handling circular 1:n references with FK settings and use of
     * auto-delete setting to delete object graph.
     */
    public void testCircularOneToN_2() throws Exception
    {
        String name = "testCircularOneToN_2_" + 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");
        Product p4 = new Product(name + "_p4");
        Product p5 = new Product(name + "_p5");
        Product p6 = new Product(name + "_p6");
        Product p7 = new Product(name + "_p7");

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        p1.addSubProduct(p2);
        p1.addSubProduct(p3);
        p3.addSubProduct(p4);
        p3.addSubProduct(p5);
        p5.addSubProduct(p6);
        p6.addSubProduct(p7);
        database.makePersistent(p1);
        // before establishing the circular references write
        // all objects to DB
        tx.flush();
        // now close the circular references
        p6.addSubProduct(p1);
        tx.commit();

        tx.begin();
        // on delete break the circular references first, then delete the
        // start object
        tx.lock(p6, Transaction.WRITE);
        tx.setCascadingDelete(Product.class, "subProducts", false);
        p6.setSubProducts(null);
        tx.flush();
        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();

        // we expect one Product object, because we set cascading delete 'false'
        // when do 'p6.setSubProducts(null);', so the '..._p7' Product will only be unlinked
        assertEquals(1, result.size());
        Product p7_new = (Product) result.iterator().next();
        assertEquals(name + "_p7", p7_new.getName());
    }

    /**
     * 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
    {
        String name = "testCircularWithAutoDeleteEnabled_" + System.currentTimeMillis();

        ojbChangeReferenceSetting(ObjectA.class, "refAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAA.class, "refAAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAAA.class, "refAAAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAAAA.class, "refA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);

        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);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        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();
        /*
        arminw: When deleting a object which is part of circular 1:1 references
        with cascade delete enabled it's mandatory to break the circular reference
        before deleting it.
        */
        tx.lock(aaaa, Transaction.WRITE);
        // break the circular references
        aaaa.setRefA(null);
        database.deletePersistent(a);
        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();
    }

    /**
     * Use auto-delete setting to delete object graph.
     */
    public void testAutoDeleteEnabledNonCircular() throws Exception
    {
        String name = "testAutoDeleteEnabledNonCircular_" + System.currentTimeMillis();

        ojbChangeReferenceSetting(ObjectA.class, "refAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAA.class, "refAAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAAA.class, "refAAAA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAAAA.class, "refA", true, ObjectReferenceDescriptor.CASCADE_NONE, ObjectReferenceDescriptor.CASCADE_OBJECT, false);

        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 references
        a.setRefAA(aa);
        aa.setRefAAA(aaa);
        aaa.setRefAAAA(aaaa);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        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();
        database.deletePersistent(a);
        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();
    }

    /**
     * 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(s1);
        tx.commit();

        tx.begin();
        database.deletePersistent(s1);
        tx.commit();
    }

    /**
     * Define order of object operations using flush() method.
     */
    public void testBidirectionalWithConstraint_1b() throws Exception
    {
        String name = "testBidirectionalWithConstraint_1b_" + System.currentTimeMillis();
        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();

        Shop s1 = new Shop(name + "_1");
        // when using flush() we can use the "natural" order
        // without getting DB constraint violence.
        database.makePersistent(s1);
        // write to DB object without references
        tx.flush();
        ShopDetail sd = new ShopDetail(name + "_1");
        // now set references
        s1.setDetail(sd);
        sd.setShop(s1);
        // no need to persist the ShopDetail object
        // (will be detected by OJB)
        // but it doesn't matter if you do
        // database.makePersistent(sd);
        tx.commit();

        tx.begin();
        // madatory to mark object with DB FK constraint first on delete
        // (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();
    }

    /**
     * If the user take care of the ordering itself the test pass.
     */
    public void testBidirectionalWithConstraint_1c() throws Exception
    {
        String name = "testBidirectionalWithConstraint_1c_" + System.currentTimeMillis();
        TransactionExt tx = (TransactionExt) odmg.newTransaction();

        Shop s1 = new Shop(name + "_1");
        ShopDetail sd = new ShopDetail(name + "_1");
        s1.setDetail(sd);
        sd.setShop(s1);

        // 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);
        tx.commit();

        // 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);
        database.deletePersistent(sd);
        tx.commit();
    }

    /**
     * This test is only for comparison of ODMG- with PB-api. It's not recommended
     * to do this in ODMG production environment.
     *
     * @throws Exception
     */
    public void testBidirectionalWithConstraint_1d_PB() throws Exception
    {
        ojbChangeReferenceSetting(Shop.class, "detail", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ShopDetail.class, "shop", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        String name = "testBidirectionalWithConstraint_1a_" + 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);

        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        tx.getBroker().store(s1);
        tx.commit();


        tx.begin();
        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        // madatory to mark object with DB FK constraint first on delete
        // then OJB will use this order to delete the bidirectional objects
        tx.getBroker().delete(s1);
        tx.commit();
    }

    /**
     * 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();
            // 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
    {
        String name = "testCircularOneToOne_1a_" + 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");
        // now set the circular references
        a.setRefAA(aa);
        aa.setRefAAA(aaa);
        aaa.setRefA(a);
        database.makePersistent(a);
        tx.commit();

        tx.begin();
        database.deletePersistent(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(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(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(0, result.size());
        tx.commit();
    }

    /**
     * Test show handling with circular references and database FK settings.
     */
    public void testCircularOneToOne_1b() throws Exception
    {
        String name = "testCircularOneToOne_1b_" + 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);
        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();
        database.deletePersistent(a);
        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(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();
    }

    /**
     * Do manually ordering using {@link TransactionExt#setOrdering(boolean)} to disable
     * OJB's ordering algorithm (and implicit locking).
     */
    public void testCircularOneToOne_1c() throws Exception
    {
        String name = "testCircularOneToOne_1d_" + 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);

        /*
        we want to manually insert new object, so we disable
        OJB's ordering and implicit object locking
        */
        tx.setOrdering(false);
        tx.setImplicitLocking(false);

        database.makePersistent(aaaa);
        database.makePersistent(aaa);
        database.makePersistent(aa);
        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();
        /*
        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);
        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 in conjunction with OJB's ordering.
     */
    public void testCircularOneToOne_1dd() throws Exception
    {
        String name = "testCircularOneToOne_1dd_" + 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);

        /*
        we manually determine the insert object order
        */
        tx.setOrdering(false);
        tx.setImplicitLocking(false);

        database.makePersistent(aaaa);
        database.makePersistent(aaa);
        database.makePersistent(aa);
        database.makePersistent(a);
        tx.commit();

        tx.begin();
        /*
        the ordering/implicit locking/noteOrdering settings are still enabled
        */
        database.deletePersistent(a);
        database.deletePersistent(aa);
        database.deletePersistent(aaa);
        database.deletePersistent(aaaa);
        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(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();
    }

    public void testCircularOneToOne_1e() throws Exception
    {
        String name = "testCircularOneToOne_1e_" + 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);

        database.makePersistent(a);
        tx.commit();

        tx.begin();
        // delete one object from an object graph
        tx.lock(aa, Transaction.WRITE);
        aa.setRefAAA(null);
        database.deletePersistent(aaa);
        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(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(1, result.size());
        tx.commit();
    }

    /**
     * User take care of the ordering itself.
     */
    public void testCircularOneToOne_2a() throws Exception
    {
        String name = "testCircularOneToOne_2_" + System.currentTimeMillis();

        ObjectA a = new ObjectA(name + "_ObjectA");
        ObjectAA aa = new ObjectAA(name + "_ObjectAA");
        ObjectAAA aaa = new ObjectAAA(name + "_ObjectAAA");
        // now set the circular references
        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);
        database.deletePersistent(aaa);
        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(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();
    }

    /**
     * This test is only for comparison of ODMG- with PB-api. It's not recommended
     * to do this in ODMG production environment.
     * Handling of circular 1:1 reference: ObjetA--1:1-->ObjectAA--1:1-->ObjectAAA--1:1-->ObjectA
     * when each object has a FK constraint to it's reference.
     *
     * @throws Exception
     */
    public void testCircularOneToOne_PB_a() throws Exception
    {
        ojbChangeReferenceSetting(ObjectA.class, "refAA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAA.class, "refAAA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        //ojbChangeReferenceSetting(ObjectAAA.class, "refA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        String name = "testCircularOneToOne_PB" + System.currentTimeMillis();
        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();

        ObjectA a = new ObjectA(name + "_ObjectA");
        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        //tx.getBroker().store(a);

        ObjectAA aa = new ObjectAA(name + "_ObjectAA");
        ObjectAAA aaa = new ObjectAAA(name + "_ObjectAAA");
        // now set the circular references
        a.setRefAA(aa);
        aa.setRefAAA(aaa);
        aaa.setRefA(a);
        tx.getBroker().store(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(0, result.size());
        tx.commit();


        tx.begin();
        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        // madatory to mark object with DB FK constraint first on delete
        // then OJB will use this order to delete the bidirectional objects
        //aaa.setRefA(null);
        //tx.getBroker().store(aaa);
        tx.getBroker().delete(a);
        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();
    }

    /**
     * This test is only for comparison of ODMG- with PB-api. It's not recommended
     * to do this in ODMG production environment.
     * Handling of circular 1:1 reference: ObjetA--1:1-->ObjectAA--1:1-->ObjectAAA--1:1-->ObjectA
     * when each object has a FK constraint to it's reference.
     *
     * @throws Exception
     */
    public void testCircularOneToOne_PB_b() throws Exception
    {
        ojbChangeReferenceSetting(ObjectA.class, "refAA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        ojbChangeReferenceSetting(ObjectAA.class, "refAAA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        //ojbChangeReferenceSetting(ObjectAAA.class, "refA", true, ObjectReferenceDescriptor.CASCADE_OBJECT, ObjectReferenceDescriptor.CASCADE_OBJECT, false);
        String name = "testCircularOneToOne_PB" + System.currentTimeMillis();
        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();

        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        //tx.getBroker().store(a);

        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);

        tx.getBroker().store(a);

        tx.commit();


        tx.begin();
        // only for testing, we completely bypass odmg
        tx.getBroker().beginTransaction();
        // madatory to mark object with DB FK constraint first on delete
        // then OJB will use this order to delete the bidirectional objects
        //aaa.setRefA(null);
        //tx.getBroker().store(aaa);
        tx.getBroker().delete(a);
        tx.commit();
    }

    /**
     * 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
    {
        String name = "testBidirectionalWithConstraint_2a_" + 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();
        database.makePersistent(s1);
        tx.commit();

        // Now we delete the Shop with ShopDetail, but don't
        // touch the Distributor object
        tx.begin();
        database.deletePersistent(s1);
        // flush to avoid constraint error
        tx.flush();
        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_2b() throws Exception
    {
        String name = "testBidirectionalWithConstraint_2c_" + System.currentTimeMillis();

        Shop s1 = new Shop(name + "_1");
        Distributor d1 = new Distributor(name + "_1");
        s1.addDistributor(d1);
        d1.addShop(s1);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        // 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, we disable implicit
        // locking and ordering to avoid constraint error
        tx.setImplicitLocking(false);
        tx.setOrdering(false);
        tx.begin();
        database.deletePersistent(d1);
        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_2d() throws Exception
    {
        String name = "testBidirectionalWithConstraint_2d_" + System.currentTimeMillis();
        Shop s1 = new Shop(name + "_1");
        ShopDetail sd = new ShopDetail(name + "_1");
        s1.setDetail(sd);
        sd.setShop(s1);
        Shop s2 = new Shop(name + "_2");
        Shop s3 = new Shop(name + "_3");
        Distributor d1 = new Distributor(name + "_1");
        Distributor d2 = new Distributor(name + "_2");
        Distributor d3 = new Distributor(name + "_3");
        Distributor d4 = new Distributor(name + "_4");
        s1.addDistributor(d1);
        d1.addShop(s1);
        s1.addDistributor(d2);
        d2.addShop(s1);
        s1.addDistributor(d3);
        d3.addShop(s1); // one
        s2.addDistributor(d1);
        d1.addShop(s2);
        s3.addDistributor(d4);
        d4.addShop(s3);
        s3.addDistributor(d1);
        d1.addShop(s3);
        d3.addShop(s2); // two
        s2.addDistributor(d3);
        d3.addShop(s3); // three
        s3.addDistributor(d3);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        // mandatory to add the ShopDetail object first, because of the ordering bug
        database.makePersistent(sd);
        database.makePersistent(s1);
        database.makePersistent(s2);
        database.makePersistent(s3);
        tx.commit();

        tx.begin();
        database.deletePersistent(d1);
        database.deletePersistent(s1);
        database.deletePersistent(d4);
        tx.commit();

        tx.begin();
        // clear the cache to make this test work with all cache implementations
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name + "%");
        Collection result = (Collection) query.execute();

        assertEquals(2, result.size());

        query = odmg.newOQLQuery();
        query.create("select objects from " + Distributor.class.getName() + " where name like $1");
        query.bind(name + "%");
        result = (Collection) query.execute();

        assertEquals(2, result.size());
        tx.commit();

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select objects from " + Distributor.class.getName() + " where name like $1");
        query.bind(name + "_3");
        result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Distributor d3New = (Distributor) result.iterator().next();

        assertNotNull(d3New.getShops());
        assertEquals(2, d3New.getShops().size());
    }

    public void testMtoNWithBackReference_2() throws Exception
    {
        String name = "testMtoNWithBackReference_2_" + System.currentTimeMillis();
        Shop s1 = new Shop(name + "_1");
        Shop s2 = new Shop(name + "_2");
        Shop s3 = new Shop(name + "_3");
        Distributor d1 = new Distributor(name + "_1");
        Distributor d2 = new Distributor(name + "_2");
        Distributor d3 = new Distributor(name + "_3");
        Distributor d4 = new Distributor(name + "_4");
        s1.addDistributor(d1);
        d1.addShop(s1);
        s1.addDistributor(d2);
        d2.addShop(s1);
        s1.addDistributor(d3);
        d3.addShop(s1);
        s2.addDistributor(d1);
        d1.addShop(s2);
        s3.addDistributor(d4);
        d4.addShop(s3);
        s3.addDistributor(d1);
        d1.addShop(s3);
        d3.addShop(s2);
        s2.addDistributor(d3);
        d3.addShop(s3);
        s3.addDistributor(d3);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        // madatory to add the ShopDetail object first
        database.makePersistent(s1);
        database.makePersistent(s2);
        database.makePersistent(s3);
        tx.commit();

        tx.begin();
        tx.setCascadingDelete(Distributor.class, "shops", true);
        database.deletePersistent(d1);
        database.deletePersistent(s1);
        database.deletePersistent(d4);
        tx.commit();

        tx.begin();
        // clear cache to make it work with all caching implementations
        tx.getBroker().clearCache();
        OQLQuery query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name + "%");
        Collection result = (Collection) query.execute();

        assertEquals(0, result.size());

        query = odmg.newOQLQuery();
        query.create("select objects from " + Distributor.class.getName() + " where name like $1");
        query.bind(name + "%");
        result = (Collection) query.execute();

        assertEquals(2, result.size());
        tx.commit();

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select objects from " + Distributor.class.getName() + " where name like $1");
        query.bind(name + "_3");
        result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Distributor d3New = (Distributor) result.iterator().next();

        assertNotNull(d3New.getShops());
        assertEquals(0, d3New.getShops().size());
    }

    public void testOneToNWithSelfReference_1() throws Exception
    {
        String name = "testOneToNWithSelfReference_1_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        Product p1 = new Product();
        p1.setName(name + "_product_1");
        Product p2 = new Product();
        p2.setName(name + "_product_2");

        List products = new ArrayList();
        products.add(p1);
        products.add(p2);

        s.setProducts(products);
        p1.setShop(s);
        p2.setShop(s);

        Product p1a = new Product();
        p1a.setName(name + "_subProduct_A");
        Product p1b = new Product();
        p1b.setName(name + "_subProduct_B");
        Product p1c = new Product();
        p1c.setName(name + "_subProduct_C");

        List subProducts = new ArrayList();
        subProducts.add(p1a);
        subProducts.add(p1b);
        subProducts.add(p1c);

        p1.setSubProducts(subProducts);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        database.makePersistent(s);
        tx.commit();

        tx.begin();
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select products from " + Shop.class.getName() + " where name like $1");
        query.bind(name + "%");
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Shop newShop = (Shop) result.iterator().next();
        assertNotNull(newShop.getProducts());
        assertEquals(2, newShop.getProducts().size());

        boolean match = false;
        for(Iterator iterator = newShop.getProducts().iterator(); iterator.hasNext();)
        {
            Product p = (Product) iterator.next();
            if(p.getSubProducts() != null && p.getSubProducts().size() > 0)
            {
                match = true;
                assertEquals(3, p.getSubProducts().size());
            }
        }
        assertTrue("Sub products aren't stored", match);

        tx.begin();
        database.deletePersistent(s);
        tx.commit();


        tx.begin();
        tx.getBroker().clearCache();
        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_subPro%");
        result = (Collection) query.execute();
        tx.commit();
        assertEquals(3, result.size());

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_product_1");
        result = (Collection) query.execute();
        assertEquals(1, result.size());

        database.deletePersistent(result.iterator().next());
        tx.commit();


        tx.begin();
        tx.getBroker().clearCache();
        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_subPro%");
        result = (Collection) query.execute();
        tx.commit();
        assertEquals(3, result.size());
    }

    public void testOneToNWithSelfReference_2() throws Exception
    {
        String name = "testOneToNWithSelfReference_2_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        Product p1 = new Product();
        p1.setName(name + "_product_1");
        Product p2 = new Product();
        p2.setName(name + "_product_2");

        List products = new ArrayList();
        products.add(p1);
        products.add(p2);

        s.setProducts(products);
        p1.setShop(s);
        p2.setShop(s);

        Product p1a = new Product();
        p1a.setName(name + "_subProduct_A");
        Product p1b = new Product();
        p1b.setName(name + "_subProduct_B");
        Product p1c = new Product();
        p1c.setName(name + "_subProduct_C");

        List subProducts = new ArrayList();
        subProducts.add(p1a);
        subProducts.add(p1b);
        subProducts.add(p1c);

        p1.setSubProducts(subProducts);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        database.makePersistent(s);
        tx.commit();

        tx.begin();
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select products from " + Shop.class.getName() + " where name like $1");
        query.bind(name + "%");
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Shop newShop = (Shop) result.iterator().next();
        assertNotNull(newShop.getProducts());
        assertEquals(2, newShop.getProducts().size());

        boolean match = false;
        for(Iterator iterator = newShop.getProducts().iterator(); iterator.hasNext();)
        {
            Product p = (Product) iterator.next();
            if(p.getSubProducts() != null && p.getSubProducts().size() > 0)
            {
                match = true;
                assertEquals(3, p.getSubProducts().size());
            }
        }
        assertTrue("Sub products aren't stored", match);

        tx.begin();
        // now we enable cascading delete
        tx.setCascadingDelete(Shop.class, true);
        database.deletePersistent(s);
        tx.commit();


        tx.begin();
        tx.getBroker().clearCache();
        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_subPro%");
        result = (Collection) query.execute();
        assertEquals(3, result.size());

        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_product_1");
        result = (Collection) query.execute();
        assertEquals(0, result.size());

        tx.commit();
    }

    public void testOneToNWithSelfReference_3() throws Exception
    {
        String name = "testOneToNWithSelfReference_3_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        Product p1 = new Product();
        p1.setName(name + "_product_1");
        Product p2 = new Product();
        p2.setName(name + "_product_2");

        List products = new ArrayList();
        products.add(p1);
        products.add(p2);

        s.setProducts(products);
        p1.setShop(s);
        p2.setShop(s);

        Product p1a = new Product();
        p1a.setName(name + "_subProduct_A");
        Product p1b = new Product();
        p1b.setName(name + "_subProduct_B");
        Product p1c = new Product();
        p1c.setName(name + "_subProduct_C");

        List subProducts = new ArrayList();
        subProducts.add(p1a);
        subProducts.add(p1b);
        subProducts.add(p1c);

        p1.setSubProducts(subProducts);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        database.makePersistent(s);
        tx.commit();

        tx.begin();
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select products from " + Shop.class.getName() + " where name like $1");
        query.bind(name + "%");
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Shop newShop = (Shop) result.iterator().next();
        assertNotNull(newShop.getProducts());
        assertEquals(2, newShop.getProducts().size());

        boolean match = false;
        for(Iterator iterator = newShop.getProducts().iterator(); iterator.hasNext();)
        {
            Product p = (Product) iterator.next();
            if(p.getSubProducts() != null && p.getSubProducts().size() > 0)
            {
                match = true;
                assertEquals(3, p.getSubProducts().size());
            }
        }
        assertTrue("Sub products aren't stored", match);

        tx.begin();
        // now we enable cascading delete
        tx.setCascadingDelete(Shop.class, true);
        tx.setCascadingDelete(Product.class, true);
        database.deletePersistent(s);
        tx.commit();


        tx.begin();
        tx.getBroker().clearCache();
        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_subPro%");
        result = (Collection) query.execute();
        assertEquals(0, result.size());

        query = odmg.newOQLQuery();
        query.create("select products from " + Product.class.getName() + " where name like $1");
        query.bind(name + "_product_1");
        result = (Collection) query.execute();
        assertEquals(0, result.size());

        tx.commit();
    }

    public void testOneToOneWithBackReference_1() throws Exception
    {
        String name = "testOneToOneWithBackReference_1_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        ShopDetail sd = new ShopDetail();
        sd.setName(name);
        s.setDetail(sd);
        sd.setShop(s);

        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();
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
        query.bind(name);
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        ShopDetail sdNew = (ShopDetail) result.iterator().next();
        assertNotNull(sdNew.getShop());

        tx.begin();
        tx.lock(sdNew, Transaction.WRITE);
        Shop tmp = sdNew.getShop();
        // it's bidirectional, so remove this references first
        tmp.setDetail(null);
        sdNew.setShop(null);
        database.deletePersistent(tmp);
        tx.flush();

        query = odmg.newOQLQuery();
        query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(1, result.size());
        ShopDetail newSd = (ShopDetail) result.iterator().next();
        assertNotNull(newSd);
        assertNull(newSd.getShop());
        tx.commit();

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name);
        Collection resultShop = (Collection) query.execute();
        assertEquals(0, resultShop.size());

        // delete ShopDetail too
        database.deletePersistent(newSd);
        tx.commit();
    }

    public void testOneToOneWithBackReference_3() throws Exception
    {
        String name = "testOneToOneWithBackReference_3_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        ShopDetail sd = new ShopDetail();
        sd.setName(name);
        s.setDetail(sd);
        sd.setShop(s);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        database.makePersistent(s);
        database.deletePersistent(s);
        database.makePersistent(s);
        tx.commit();

        tx.begin();
        OQLQuery query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name);
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        Shop newShop = (Shop) result.iterator().next();
        assertNotNull(newShop.getDetail());

        tx.begin();
        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");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(0, result.size());

        query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(0, result.size());
        tx.commit();

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(0, result.size());

        query = odmg.newOQLQuery();
        query.create("select shops from " + Shop.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(0, result.size());
        tx.commit();
    }

    public void testOneToOneWithBackReference_2() throws Exception
    {
        String name = "testOneToOneWithBackReference_2_" + System.currentTimeMillis();
        Shop s = new Shop();
        s.setName(name);
        ShopDetail sd = new ShopDetail();
        sd.setName(name);
        s.setDetail(sd);
        sd.setShop(s);

        TransactionExt tx = (TransactionExt) odmg.newTransaction();
        tx.begin();
        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();
        tx.getBroker().clearCache();

        OQLQuery query = odmg.newOQLQuery();
        query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
        query.bind(name);
        Collection result = (Collection) query.execute();
        tx.commit();

        assertEquals(1, result.size());
        ShopDetail sdNew = (ShopDetail) result.iterator().next();
        assertNotNull(sdNew.getShop());

        tx.begin();
        // cascading delete should delete Shop too
        tx.setCascadingDelete(ShopDetail.class, true);
        database.deletePersistent(sdNew);
        tx.flush();

        query = odmg.newOQLQuery();
        query.create("select detail from " + ShopDetail.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        tx.commit();
        assertEquals(0, result.size());

        tx.begin();
        query = odmg.newOQLQuery();
        query.create("select detail from " + Shop.class.getName() + " where name like $1");
        query.bind(name);
        result = (Collection) query.execute();
        assertEquals(0, result.size());
        tx.commit();
    }

    public static class Shop
    {
        private Integer id;
        private String name;
        private ShopDetail detail;
        private List products;
        private List distributors;

        public Shop()
        {
        }

        public Shop(String name)
        {
            this.name = name;
        }

        public Integer getId()
        {
            return id;
        }

        public void setId(Integer id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public ShopDetail getDetail()
        {
            return detail;
        }

        public void setDetail(ShopDetail detail)
        {
            this.detail = detail;
        }

        public List getProducts()
        {
            return products;
        }

        public void setProducts(List products)
        {
            this.products = products;
        }

        public List getDistributors()
        {
            return distributors;
        }

        public void setDistributors(List distributors)
        {
            this.distributors = distributors;
        }

        public void addDistributor(Distributor d)
        {
            if(this.distributors == null)
            {
                this.distributors = new ArrayList();
            }
            this.distributors.add(d);
        }
    }

    public static class Distributor
    {
        private Integer id;
        private String name;
        private List shops;

        public Distributor()
        {
        }

        public Distributor(String name)
        {
            this.name = name;
        }

        public Integer getId()
        {
            return id;
        }

        public void setId(Integer id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public List getShops()
        {
            return shops;
        }

        public void setShops(List shops)
        {
            this.shops = shops;
        }

        public void addShop(Shop s)
        {
            if(this.shops == null)
            {
                this.shops = new ArrayList();
            }
            this.shops.add(s);
        }
    }

    public static class Product
    {
        private Integer id;
        private String name;
        private Shop shop;
        private Integer shopFk;
        private List subProducts;
        private Integer subProductFK;

        public Product()
        {
        }

        public Product(String name)
        {
            this.name = name;
        }

        public Integer getId()
        {
            return id;
        }

        public void setId(Integer id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public Shop getShop()
        {
            return shop;
        }

        public void setShop(Shop shop)
        {
            this.shop = shop;
        }

        public Integer getShopFk()
        {
            return shopFk;
        }

        public void setShopFk(Integer shopFk)
        {
            this.shopFk = shopFk;
        }

        public Integer getSubProductFK()
        {
            return subProductFK;
        }

        public void setSubProductFK(Integer subProductFK)
        {
            this.subProductFK = subProductFK;
        }

        public void addSubProduct(Product p)
        {
            if(subProducts == null)
            {
                subProducts = new ArrayList();
            }
            subProducts.add(p);
        }

        public List getSubProducts()
        {
            return subProducts;
        }

        public void setSubProducts(List subProducts)
        {
            this.subProducts = subProducts;
        }
    }

    public static class ShopDetail
    {
        private Integer id;
        private String name;
        private Shop shop;

        public ShopDetail()
        {
        }

        public ShopDetail(String name)
        {
            this.name = name;
        }

        public Integer getId()
        {
            return id;
        }

        public void setId(Integer id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public Shop getShop()
        {
            return shop;
        }

        public void setShop(Shop shop)
        {
            this.shop = shop;
        }
    }

    abstract static class BaseObject
    {
        private Integer id;
        private String name;
        private String ojbConcreteClass;

        public BaseObject()
        {
            this.ojbConcreteClass = this.getClass().getName();
        }

        public BaseObject(String name)
        {
            this();
            this.name = name;
        }

        public Integer getId()
        {
            return id;
        }

        public void setId(Integer id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        public String getOjbConcreteClass()
        {
            return ojbConcreteClass;
        }

        public void setOjbConcreteClass(String ojbConcreteClass)
        {
            this.ojbConcreteClass = ojbConcreteClass;
        }
    }

    public static class ObjectA extends BaseObject
    {
        private ObjectAA refAA;

        public ObjectA()
        {
        }

        public ObjectA(String name)
        {
            super(name);
        }

        public ObjectAA getRefAA()
        {
            return refAA;
        }

        public void setRefAA(ObjectAA refAA)
        {
            this.refAA = refAA;
        }
    }

    public static class ObjectAA extends BaseObject
    {
        private ObjectAAA refAAA;

        public ObjectAA()
        {
        }

        public ObjectAA(String name)
        {
            super(name);
        }

        public ObjectAAA getRefAAA()
        {
            return refAAA;
        }

        public void setRefAAA(ObjectAAA refAAA)
        {
            this.refAAA = refAAA;
        }
    }

    public static class ObjectAAA extends BaseObject
    {
        private ObjectAAAA refAAAA;
        private ObjectA refA;

        public ObjectAAA()
        {
        }

        public ObjectAAA(String name)
        {
            super(name);
        }

        public ObjectAAAA getRefAAAA()
        {
            return refAAAA;
        }

        public void setRefAAAA(ObjectAAAA refAAAA)
        {
            this.refAAAA = refAAAA;
        }

        public ObjectA getRefA()
        {
            return refA;
        }

        public void setRefA(ObjectA refA)
        {
            this.refA = refA;
        }
    }

    public static class ObjectAAAA extends BaseObject
    {
        private ObjectA refA;

        public ObjectAAAA()
        {
        }

        public ObjectAAAA(String name)
        {
            super(name);
        }

        public ObjectA getRefA()
        {
            return refA;
        }

        public void setRefA(ObjectA refA)
        {
            this.refA = refA;
        }
    }
}
TOP

Related Classes of org.apache.ojb.odmg.CircularTest$ObjectAAAA

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.