Status/Plans on Inheritance?

From: Arndt Brenschede (a..iamos.de)
Date: Sun Mar 02 2003 - 15:08:19 EST

  • Next message: Holger Hoffstätte: "Re: Modeler vs. consistency of DataMap/Entity/Attribute/Relationship"

    Hi

    sorry to bother you again :-)

    Our object model uses inheritance,
    which is not supported by cayenne.

    (Actually, it *is* supported in
    the modeler and the mapping-DTD,
    which can be confusing, because
    modeling inheritance results in
    runtime error about non-existing
    relations)

    I tried some changes to make
    inheritance work, and that works,
    as far as my tests are concerned.

     From the discussion in the mailing
    lists it seems that inheritance is
    something you have in mind or are
    working on, so I will not send you
    any patches, but just discuss the
    problems I encounterd.

    - First problem is *who* decides from
       the data-row which class to instanciate
       for the data-object.

       I put that as application code in the
       data-object itself, by extending the
       DataObject-interface by a method
       "createNewInstance" (see attached file
       "Person.java", with "Customer" and "Employee"
       extending "Person")

       Instrumenting the methods
       objectFromDataRow/registeredObject
       in DataContext to call "createNewInstance"
       ensures that the correct type is instanciated
       if a data-row is available.

    - Second problem is how to deal with
       "Hollow" objects where the type is not
       known. There are basically 2 solutions:
        - the type is part of the ObjectId,
          so it is always known
        - or hollow objects with inheritance
          are instances of the base-class,
          but never "published"

        I used the second solution. That means
        a mechanism in "CayenneDataObject"
        to refetch a Hollow object when it
        is read via "readProperty"

    - Third problem is how to "inherit"
       the attributes and relationships
       accross the "ObjEntity"'s.
       I used a mechanism to copy
       (after loading the map)
       the attributes and relations down
       the inheritance hirachies, so
       that every instance of ObjEntity
       has at runtime it's full list of
       attributes and relationships.
       (This is of course a *BAD* solution,
       because this means
       to use at runtime a different
       representation of inheritance then
       in the model - an indeed this needs
       another workaround to prevent
       the modeler from doing that and
       destroying the mapping-file....
       But the "correct" solution of
       following the inheritance at
       runtime (when getAttributeList()
       is called) is probably more
       work to implement and more
       processing at runtime)

    - fourth problem is to make the
       queries quering the "superset"
       of all attributes for all possible
       types.
       I did that by adding in ObjEntity
       the "superset" list of attributes
       and a method "getAttributeSuperSetList()"
       that I called from within "SelectTranslator"
       instead of "getAttributeList()"
       (same for relations)

    This is all not really nice, but when
    it comes to inheritance, one death you
    have to die... (but anyway, it works)

    Any comment on what what you think
    about these problems/options/strategies
    and if and when cayenne will support inheritance?

    thanks,

    Arndt

    import java.util.Map;
    import org.objectstyle.cayenne.DataObject;

    public class Person extends _Person {

        public static final int PERSON = 1;
        public static final int EMPLOYEE = 2;
        public static final int CUSTOMER = 3;

        public Person() {
           super();
           setTyp( new Integer( PERSON ) );
        }

        public DataObject createNewInstance(Map map) {

           // this is used to determine if this
           // objects features inheritance
           if ( map == null ) {
              return this;
           }

           Integer iTyp = (Integer)map.get("TYP");
           int typ = ( iTyp == null ? 0: iTyp.intValue() );

           DataObject obj = null;
           switch ( typ ) {
              case PERSON : obj = new Person(); break;
              case EMPLOYEE : obj = new Employee(); break;
              case CUSTOMER : obj = new Customer(); break;
              default : obj = null;
           }
           if ( obj != null ) {
              copyInternalState( obj );
              return obj;
           } else {
              return this;
           }
        }
    }



    This archive was generated by hypermail 2.0.0 : Sun Mar 02 2003 - 14:54:29 EST