Thomas Dudziak wrote:
Vadim Gritsenko wrote:

Hey All,

[Using OJB_1_0_RELEASE branch from CVS]

As other users here, I'm also struggling with mapping class hierarchy on multiple joined tables, and can't figure out what's wrong and whether it is working at all or not.

Consider this slightly modified (added relation to the class C) example from the OJB manual page [1]:

/**
 * @ojb.class
 * @ojb.extent-class class-ref="B"
 */
public class A {
    /** @ojb.field primarykey="true" autoincrement="ojb" */
    Integer id;
    /** @ojb.field */
    Integer cId;
    /** @ojb.reference foreignkey="cId" */
    C c;
}

/**
 * @ojb.class include-inherited="false"
 * @ojb.reference class-ref="A" foreignkey="aId"
 *     auto-retrieve="true" auto-update="object" auto-delete="object"
 */
public class B extends A
{
    /** @ojb.field primarykey="true" autoincrement="ojb" */
    Integer id;
    /** @ojb.field */
    Integer aId;
    /** @ojb.field length="254" */
    String value;
}

/**
 * @ojb.class
 */
public class C {
    /** @ojb.field primarykey="true" autoincrement="ojb" */
    Integer id;
    /** @ojb.field length="30" */
    String name;

/** @ojb.collection element-class-ref="A" foreignkey="cId" */ Collection a;

}


Ok, once we have that, problems start. First problem is that xdoclet does not like include-inherited="false", and when include-inherited="true", it generates all inherited attributes into repository.xml - but we don't want them there! After some patching of xdoclet [2], we can get desired result:


Mhmm, don't know what version of the XDoclet module you're using but with the classes that you posted it works for me out-of-the-box (current version that comes with 1.0.1)

I'm sorry, I forgot to add Collection of A's in C (see above). With this collection, xdoclet fails - for both 1.0.1 release and 1.0.x branch (I'm working off the branch as mentioned above).



and generates exactly this repository file:


<class-descriptor class="A" table="A_TABLE"> <extent-class class-ref="B"/> <field-descriptor name="id" column="id" jdbc-type="INTEGER" primarykey="true" autoincrement="true"/> <field-descriptor name="cId" column="cId" jdbc-type="INTEGER"/> <reference-descriptor name="c" class-ref="C"> <foreignkey field-ref="cId"/> </reference-descriptor> </class-descriptor>

<class-descriptor class="B" table="B_TABLE">
  <field-descriptor name="id" column="id" jdbc-type="INTEGER"
                    primarykey="true" autoincrement="true"/>
  <field-descriptor name="aId" column="aId" jdbc-type="INTEGER"/>
  <field-descriptor name="value" column="value"
                    jdbc-type="VARCHAR" length="254"/>
  <reference-descriptor name="super" class-ref="A"
       auto-retrieve="true" auto-update="object" auto-delete="object">
    <foreignkey field-ref="aId"/>
  </reference-descriptor>
</class-descriptor>

<class-descriptor class="C" table="C_TABLE">
  <field-descriptor name="id" column="id" jdbc-type="INTEGER"
                    primarykey="true" autoincrement="true"/>
  <field-descriptor name="value" column="value"
                    jdbc-type="VARCHAR" length="30"/>

<collection-descriptor name="a" element-class-ref="A"> <inverse-foreignkey field-ref="cId"/> </collection-descriptor>

</class-descriptor>


Assuming that all of the above is correct, I'm getting following problems on run time:


1. First problem happens when trying to create instance of B (and assuming that there is a record for C) with the code:
B b = new B();
b.cId = 1;
b.value = "dummy";
broker.store(b);
This fails with KeyConstraintViolatedException. Seems it is happening because B's ClassDescriptor.getSuperClass() returns null and PersistentBrokerImpl.storeToDb does not store base class. So what's wrong, and can somebody clarify what's the difference between getBaseClass and getSuperClass methods? At least getBaseClass() is populated correctly.


I'm no expert on the mapping to multiple tables, but this is actually a SQL exception coming from the database (I suspect Hsqldb in your case) saying that the foreignkey constraint is violated while inserting a row into the A table. This can only mean that the referenced C object is not present.

Yes, it is not: first, you have to create record in table C, before trying inserting record into table A. More on this below...



You can turn off the generation of the foreign key constraints via the generate-foreignkey attribute of the torqueschema Ant task

But it's not desirable - fk constraints are a good thing to have.


2. Second problem happens when trying to load existing instance from the DB. Fails with OJBRuntimeException "Incorrect or not found field reference name 'cId' in descriptor <here comes A's CollectionDescriptor> for class-descriptor 'B'.
Seems like ObjectReferenceDescriptor does not take into account B's super class at all.


Strange, this code works just fine for me:

       B bObj = new B();
       C cObj = new C();

       cObj.name  = "The C instance";
       bObj.value = "The B instance";
       bObj.c     = cObj;

PersistenceBroker broker = PersistenceBrokerFactory.defaultPersistenceBroker();

       broker.beginTransaction();
       broker.store(bObj);
       broker.commitTransaction();
       broker.close();

       bObj = null;
       cObj = null;

       Criteria criteria = new Criteria();

       criteria.addEqualTo("value", "The B instance");

       QueryByCriteria query = new QueryByCriteria(B.class, criteria);

broker = PersistenceBrokerFactory.defaultPersistenceBroker();
broker.beginTransaction();
bObj = (B)broker.getObjectByQuery(query);
broker.abortTransaction();
System.out.println("Loaded B: '"+bObj.value+"' referencing C: '"+bObj.c.name+"'");

Well, it's getting more strange still... I ran your code (without modifying C class) and got (starting with first insert):


[org.apache.ojb.broker.accesslayer.sql.SqlGeneratorDefaultImpl] DEBUG: SQL:INSERT INTO A (id,cId) VALUES (?,?)
[org.apache.ojb.broker.accesslayer.JdbcAccessImpl] DEBUG: executeInsert: [EMAIL PROTECTED]
Exception in thread "main" org.apache.ojb.broker.KeyConstraintViolatedException: SQL failure while insert object data fo
r class A, PK of the given object is [ id=42], object was [EMAIL PROTECTED], exception message is [Integrity constraint violatio
n: A_FK_1 table: C in statement [INSERT INTO A (id,cId) VALUES (42,41) ]]
at org.apache.ojb.broker.accesslayer.JdbcAccessImpl.executeInsert(JdbcAccessImpl.java:239)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.storeToDb(PersistenceBrokerImpl.java:1642)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.store(PersistenceBrokerImpl.java:1557)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.store(PersistenceBrokerImpl.java:715)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.storeAndLinkOneToOne(PersistenceBrokerImpl.java:772)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.storeReferences(PersistenceBrokerImpl.java:755)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.storeToDb(PersistenceBrokerImpl.java:1594)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.store(PersistenceBrokerImpl.java:1557)
at org.apache.ojb.broker.core.PersistenceBrokerImpl.store(PersistenceBrokerImpl.java:715)
at org.apache.ojb.broker.core.DelegatingPersistenceBroker.store(DelegatingPersistenceBroker.java:175)
at org.apache.ojb.broker.core.DelegatingPersistenceBroker.store(DelegatingPersistenceBroker.java:175)
at Test.main(Unknown Source)


As you can see, first insert happens for A, not for C - which is, IIUC, wrong. So, what's the difference - why it was working for you?

Using ojb-blank, with hsqldb (just for testing). If it helps, you can get all code here:
http://reverycodes.com/apache/ojb/ojb-blank-abc.zip



Thanks, Vadim


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



Reply via email to