OK, I got the test case working (thanks to my trusty debugger). I had to statically initialise the collection property (listOfB) instead of initialising it on first access. As the code is written below, OJB never sees the List/Vector. If I declare listOfB with 'private Vector listOfB = new Vector()' it works. Is this a bug?

The query on A_B is still wierd though. The where clause is being ignored and every column from A_B is being returned twice! Changing it back to correct OQL still fails. I'm just not having much luck with OJB at the moment.

Since my test case now works (more or less) I'm going back to the drawing board to try and figure out why my real code keeps getting a 'transaction not in progress' error.

L.

Laurie Harper wrote:

This is driving me slightly nuts :-) I ran into a strange error tring to
add a collection property modelled by an indirection table in the
database. If I do this (much abreviated):

tx = odmg.newTransaction();
tx.begin();
tx.lock(project, WRITE);
project.getList().add(foo);
tx.commit();

where the getList() method initialises the collection property to 'new
LinkedList()' if it's not already set, I get an error about there being
no transaction in progress. That's the problem I want to solve.


In trying to understand what's going on, I tried to boil it down to a
really simple test case. The test case consists of two classes and three
tables modelling an n:m relationship. The problem is, it breaks in a
different way than the above: when I add items to the collection
property and commit, the indirection table isn't updated (so the
collection property doesn't get persisted).

The test case involves two simple classes, A and B. A has a collection
of B. The database contains tables A and B and an indirection table A_B.
I can load an instance of A from the database and OJB uses rows from A_B
to populate A's collection property. But if I try and modify the
collection property on A, nothing is written to the A_B table. Here's
the various files that constitute my test case. Any suggestions what I'm
doing wrong may help shed light on real problem, described above.

One oddity is that the query to load the AB instances only works if I
use the SQL table/column names in the OQL query! (see lines marked XXX
in the test case below). I'm unclear about why that should be...

Schema:

CREATE SEQUENCE A_SEQ;
CREATE SEQUENCE B_SEQ;
CREATE SEQUENCE A_B_SEQ;

CREATE TABLE A
(
ID INTEGER DEFAULT nextval('A_SEQ') NOT NULL,
PRIMARY KEY (ID)
);

CREATE TABLE B
(
ID INTEGER DEFAULT nextval('B_SEQ') NOT NULL,
PRIMARY KEY (ID)
);


CREATE TABLE A_B
(
A_ID INTEGER DEFAULT nextval('A_B_SEQ') NOT NULL,
B_ID INTEGER DEFAULT nextval('A_B_SEQ') NOT NULL,
PRIMARY KEY (A_ID,B_ID)
);

ALTER TABLE A_B
ADD CONSTRAINT A_FK_1 FOREIGN KEY (A_ID) REFERENCES A (ID)
;
ALTER TABLE A_B
ADD CONSTRAINT A_FK_2 FOREIGN KEY (B_ID) REFERENCES B (ID)
;

Repository_user.xml entries:




















Object model:

import java.util.List;
import java.util.LinkedList;

/**
* A has n:m relationship with B
*/
public class A {
private int id;
public int getID() {
return id;
}

private List listOfB;
public List getListOfB() {
return (null == listOfB) ? new LinkedList() : listOfB;
}
}

/* --- */

import java.util.List;

/**
* B has m:n relationship with A
*/
public class B {
private int id;
public int getID() {
return id;
}
}

/* --- */

import java.util.List;
import java.util.LinkedList;

/**
* Expose the A_B table so we can query it in the test cases.
*/
public class AB {
private int aID, bID;
public int getAID() {
return aID;
}
public int getBID() {
return bID;
}
}

Test case:

import java.util.List;

import org.odmg.*;
import org.apache.ojb.odmg.OJB;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.framework.Test;
import junit.textui.TestRunner;

/**
* Creates instances of A and B that reference each other and persists them.
*/
public class RelationshipTest extends TestCase {
private Implementation odmg;
private Database db;

public static void main(String[] args) {
TestRunner.run(RelationshipTest.class);
}
public static Test suite() {
return new TestSuite(RelationshipTest.class);
}
public RelationshipTest(String name) {
super(name);
}

public void setUp() throws ODMGException {
System.out.println("setup");
odmg = OJB.getInstance();
db = odmg.newDatabase();
db.open("repository.xml", Database.OPEN_READ_WRITE);
}

public void testCreate() throws Exception {
A a1;
B b1, b2;

// Create instances of B to be associated with an A
{
Transaction tx1 = odmg.newTransaction();
tx1.begin();
b1 = new B();
b2 = new B();
tx1.lock(b1, Transaction.WRITE);
tx1.lock(b2, Transaction.WRITE);
tx1.commit();
}

// Create an instance of A
{
Transaction tx2 = odmg.newTransaction();
tx2.begin();
a1 = new A();
tx2.lock(a1, Transaction.WRITE);
tx2.commit();
}

// Modify A's collection of Bs
{
Transaction tx3 = odmg.newTransaction();
tx3.begin();
List bs = a1.getListOfB(); // creates new list in a1
bs.add(b1);
bs.add(b2);
tx3.commit();
}

// Check that the A_B table was populated
{
OQLQuery q = odmg.newOQLQuery();
//q.create("select AB from AB where AB.aID = "+a1.getID());//XXX
q.create("select AB from AB where A_B.A_ID = "+a1.getID());//XXX
List abs = (DList) q.execute();
assertNotNull("abs", abs);
assertEquals("abs.size", 2, abs.size());
}
}

public void testLoad() throws Exception {
OQLQuery q = odmg.newOQLQuery();
q.create("select A from A where A.ID = 1");
A a = (A) ((DList) q.execute()).get(0);
List listOfB = a.getListOfB();

assertEquals("a.id", 1, a.getID());
assertNotNull("a.listOfB", listOfB);
assertEquals("a.bs.size", 2, listOfB.size());
assertEquals("a.bs[0].id", 1, ((B) listOfB.get(0)).getID());
assertEquals("a.bs[1].id", 2, ((B) listOfB.get(1)).getID());
}
}


--
To unsubscribe, e-mail:
For additional commands, e-mail:

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to