Bruce,

I changed out the use of native arrays and changed it
back to using ArrayList for the many relationship so
I don't get the problem with arrays noted below.

I do think there needs to be some careful examination
of using arrays as collection types since JavaBeans
compliance requires using getters and setters that
take an array. My work around was to provide castor
getters and setters that access the ArrayList and
have the JavaBeans arrays convert to and from the
arrayList. Anyway, that is not the problem at hand

As for the current problem that part of a muliple 
primary key can't be a foreign key to another table.
I was able to run my app past the hard stop of the
the column names check (see below) and got as far as:

org.exolab.castor.jdo.PersistenceException: Cannot create object of type 
com.siterra.model.ObjectAttributeImpl with null identity field and no key generator
        at org.exolab.castor.jdo.engine.SQLEngine.create(SQLEngine.java:528)

The above execption is thrown when the class is not an extension,
there is no key generator, and the identity is null as follows:
if ( _extends == null && _keyGen == null && identity == null )

I have manually set the "attribute" column of the identity of
ObjectAttributeImpl. The code needs to set the objectId from 
the id of the Parent Object based on the foreign key relationship.
I don't think that the code is setting the objectId on the
dependent objects (ObjectAttributeImpl).


I poked around a bit and saw that TransactionContext.create
calls markCreate to mark all of the objects to create
and then iterates through all of the marked entities and creates them
in order according to their priority as follows:

      // After the marking is done, we will actually create the object.
      // However, because some objects contains foreign key are key 
      // generated, such object should be created after some other.
      // We iterate all object and creating object according the priority.
        int         priority  = 0;
        int         nextPrior = 0;
      for ( boolean nextCreate=walk; nextCreate; priority=nextPrior ) {
          if ( enumEntry.molder.getPriority() <= priority ) {
                ...
                OID oid = enumEntry.engine.create ( this, enumEntry.oid, 
enumEntry.object );
                ...
          } else {
                nextPrior = Math.min( priority+1, enumEntry.molder.getPriority() );
                nextCreate = true;
          }
        }

In its call to ClassMoulder.getPriority() a check is made on each of the FieldMoulders
to see if the priority should be increased thereby delay creation until the object
that it depends upon is created.

    /**
     * Determines the create priority of the data object class represented by
     * this ClassMolder. Concpetually, this method determines the order of
     * which data object should be created. Priority of zero means the object
     * can be created without depending on other data object.
     *
     * This method should only be called after DatingService is closed.
     */
    public int getPriority() {
        if ( _priority == -1 ) {
            int maxPrior = 0;
            for ( int i = 0; i < _fhs.length; i++ ) {
                if ( _fhs[i].isPersistanceCapable()
                        && _fhs[i].getEnclosingClassMolder() != this
                        && _fhs[i].getFieldClassMolder() != this
                        && _fhs[i].isStored()
                        && _fhs[i].getFieldClassMolder().isKeyGeneratorUsed() ) {
                    maxPrior = Math.max( maxPrior, 
_fhs[i].getFieldClassMolder().getPriority()+1 );
                }
                /* should an "if case" for add _ids[i].isForeginKey() in the future */
           }
            _priority  = maxPrior;
        }
        return _priority;
    }

****BINGO!!!!**** 
Notice /* should an "if case" for add _ids[i].isForeginKey() in the future */
******************

The check of each field above includes a check for isKGeneratorUsed which is never true
in the case where the primary key is also part of a foreign key. Therefore the 
priority is not
getting raised for this dependent object as it should be.

Once the priority not being raised bug above is fixed, there needs to be some code 
that inserts the new master id
into the foreign key column in the dependent object. 

Bruce, What do you think. Is the priority not being raised due to 
the lack of the check for isForeignKey the problem? Also, if we put
the check in for isForeignKey and raise the priority of the dependent
object correctly. Is there code that will insert the identity into the
dependent object so that it won't throw the exception from
if ( _extends == null && _keyGen == null && identity == null )
in SQLEngine.create()

Thanks,
Ron
This one time, at band camp, Ron Ridenour said:

RR>I printed out the names of the columns on each side of the
RR>join in SQLEngine.FieldInfo as follows:
RR>
RR>[STDOUT]     SQLEngine.FieldInfo.FieldInfo(): relname:
RR>[STDOUT]         SQLEngine.FieldInfo.FieldInfo(): relname: 0 : OBJECTID
RR>[STDOUT]         SQLEngine.FieldInfo.FieldInfo(): relname: 1 : ATTRIBUTE
RR>[STDOUT]     SQLEngine.FieldInfo.FieldInfo(): classids.names:
RR>[STDOUT]         SQLEngine.FieldInfo.FieldInfo(): classids.names: 0 : OBJECTID
RR>
RR>I then commented out the check for the same number
RR>of columns on each side as follows:
RR>
RR>// basic check of column names
RR>// if ( names != null && names.length != relids.length )
RR>//  throw new MappingException("The number of column of foreign keys doesn't not 
match     with what specified in manyKey");
RR>// if ( joins != null && joins.length != classids.length )
RR>//  throw new MappingException("The number of column of foreign keys doesn't not 
match with what specified in manyKey");
RR>
RR>Perhaps all we need to do is comment out
RR>this code and test what happens. Maybe that is what was meant by the statement
RR>that went something like "there is nothing preventing using this feature. we
RR>just need to test [not the actual quote]"
RR>
RR>Question 1. Why are there 2 columns on the relname side? I declared
RR>in the mapping file that the many-key was objectId not objectid and attribute.
RR>Could this be part of the problem? Is castor properly mapping the foreign
RR>key or is it just using the primary key on the detail table by mistake? I
RR>don't know enough about what is happing to make an educated guess.
RR>
RR>Once I have removed the check I get the following error:
RR>
RR>The return type for method public com.siterra.model.ObjectAttributeImpl[] 
com.siterra.model.SiterraObjectImpl.getObjectAttributes() does not match the declared 
field type [Ljava.lang.Object;
RR>from FieldMoulder.findAccessor() in the following code:
RR>
RR>} else if ( ! Types.typeFromPrimitive( method.getReturnType() ).isAssignableFrom( 
Types.typeFromPrimitive( fieldType ) ) )
RR>//else if ( ! Types.typeFromPrimitive( fieldType ).isAssignableFrom( 
Types.typeFromPrimitive( method.getReturnType() ) ) )
RR> throw new MappingException( "mapping.accessorReturnTypeMismatch", method, 
fieldType.getName() );
RR>
RR>Question 2. getCollectionType() returns java.lang.Object.class
RR>when the collection type is set to "array"
RR>The above check then goes on to complain that the return
RR>type of the get method ObjectAttributeImpl[]
RR>is not the same as the declared type java.lang.Object.
RR>Shouldn't getCollectionType() check the type attribute in the
RR>case where the collection is an array?

Ron,

Over the weekend I was able to build a quick example of a compound
primary key. However, I don't have it working completely just because
of time (I'm under the gun at work). I'm willing to continue debugging
this problem if you can help me out a bit. How about I send you my
test case and we go work on it together?

Let me know and I'll send you the test case.

Bruce

----------------------------------------------------------- 
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
        unsubscribe castor-dev

Reply via email to