2 Replies Latest reply on Jul 21, 2004 2:45 AM by Alexey Loubyansky

    CMR with composite primary key: design choices?

    Mark Slater Newbie

      I'm still getting my J2EE legs, and I'm writing a tech demonstration to get a feel for JBoss/XDoclet as well as to serve as an example for others who will be helping me on this project in the future. Since I'm new at this, I'm not sure how I should handle a particular kind of relationship, and I'm hoping others might have some good suggestions.

      My app is tracking relationships among people. The database has a Person table and a Relationship table (to keep track of relationship types), each of which have an integer primary key (PersonID, RelationshipID). There's also a Relations table which identifies the two people in (owner and target) and type of each relationship, but in this table, the primary key is the combination of all three columns.

      Basically, I'm trying to figure out if it is more appropriate to define the CMR in the PersonBean class or if I should make a RelationBean class and define the CMR there. I've been working on the latter, and got to the point where I can deploy a cactified EAR with all my beans; performing the cactus tests though, I get an exception (org.postgresql.util.PSQLException: ERROR: invalid input syntax for type bigint) during the tearDown() function when it tries to delete the Person beans it created for the test; there are no relationships added in the PersonBean cactus tests, and without the new RelationBean the cactus tests all pass.

      If its more appropriate to put this in the PersonBean (and not have a RelationBean???), how would I define that relationship in XDoclet? Especially, how would I create finder methods that return all relationships a particular person is involved in, with the person and the type of each relationship?

      If my current method is the best way, how would I change the name of the methods to be more appropriate. Right now, I've got getOwnerId, getPersonId, and getRelId because these names are used in the table for the column names. Since they're CMR fields, and they return object types (not the integer IDs that are stored in the table), I'd prefer to use something like getOwner, getTarget, and getType. When I tried that (initially), JBoss complained that the owner column doesn't exist (which was true... the column is an integer type and called ownerId).

      Here's my RelationBean code:

       /**
       * @ejb.create-method
       */
       public RelationsKey ejbCreate(
       MrPerson ownerId, MrPerson relationId, MrRelationships relTypeId )
       throws CreateException
       {
       setOwnerId( ownerId );
       setRelationId( relationId );
       setRelId( relTypeId );
      
       return( null );
       }
      
       /**
       * This returns the owner for this relation. It is based on the relationship between
       * MrRelations and MrPerson.
       *
       * @ejb.interface-method view-type="local"
       *
       * @ejb.pk-field
       * @ejb.persistence table-name="mr_relations"
       *
       * @ejb.relation name="Relation-Owner"
       * role-name="relation-has-owner"
       * cascade-delete="no"
       * target-ejb="MrPersonBean"
       * target-role-name="owner-of-relation"
       * target-cascade-delete="no"
       *
       * @jboss.relation related-pk-field="personId"
       * fk-column="ownerId"
       * fk-constraint="true"
       *
       * @jboss.relation-mapping style="foreign-key"
       * @jboss.column-name name="ownerId"
       */
       public abstract MrPerson getOwnerId();
       public abstract void setOwnerId( MrPerson newOwner );
      
       /**
       * This returns the related person for this relation. It is based on the relationship between
       * MrRelations and MrPerson.
       *
       * @ejb.interface-method view-type="local"
       *
       * @ejb.pk-field
       * @ejb.persistence table-name="mr_relations"
       *
       * @ejb.relation name="Relation-Target"
       * role-name="relation-has-target"
       * cascade-delete="no"
       * target-ejb="MrPersonBean"
       * target-role-name="target-of-relation"
       * target-cascade-delete="no"
       *
       * @jboss.relation related-pk-field="personId"
       * fk-column="relationId"
       * fk-constraint="true"
       *
       * @jboss.relation-mapping style="foreign-key"
       * @jboss.column-name name="relationId"
       */
       public abstract MrPerson getRelationId();
       public abstract void setRelationId( MrPerson newRelation );
      
       /**
       * This returns the relationship type for this relation. It is based on the relationship
       * between MrRelations and MrRelationships.
       *
       * @ejb.interface-method view-type="local"
       *
       * @ejb.pk-field
       * @ejb.persistence table-name="mr_relations"
       *
       * @ejb.relation name="Relation-Type"
       * role-name="relation-has-type"
       * cascade-delete="no"
       * target-ejb="MrRelationshipsBean"
       * target-role-name="type-of-relation"
       * target-cascade-delete="no"
       *
       * @jboss.relation related-pk-field="relId"
       * fk-column="relId"
       * fk-constraint="true"
       *
       * @jboss.relation-mapping style="foreign-key"
       * @jboss.column-name name="relId"
       */
       public abstract MrRelationships getRelId();
       public abstract void setRelId( MrRelationships newRelationship );
      


      Thanks!