db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject cvs commit: db-ojb/xdocs howto-use-anonymous-keys.xml
Date Thu, 15 May 2003 06:20:58 GMT
thma        2003/05/14 23:20:58

  Added:       xdocs    howto-use-anonymous-keys.xml
  Log:
  add a howto on anonymous fields
  
  Revision  Changes    Path
  1.1                  db-ojb/xdocs/howto-use-anonymous-keys.xml
  
  Index: howto-use-anonymous-keys.xml
  ===================================================================
  <?xml version="1.0"?>
  <document>
  
    <properties>
      <author email="brian@skife.org">Brian McCallister</author>
      <title>ObJectRelationalBridge - HOWTO Use Anonymous Keys</title>
    </properties>
  
  <body>
  
  <section name="HOWTO Use Anonymous Keys">
  	<subsection name="Why Do We Need Anonymous Keys?">
  		<p>
  		The core difference between referential integrity in Java and in an RDBMS lies in where
the specific referential information is maintained. Java, and most modern OO languages, maintain
referential integrity information in the runtime environment. Actual object relationships
are maintained by the virtual machine so that the symbolic variable used in the application
is dereferenced it will in fact provide access to the object instance which it is expected
to provide access to. There is no need for a manual lookup or search across the heap for the
correct object instance. Entity reference integrity is maintained and handled for the programmer
by the environment.
  		</p>
  		<p>
  		Relational databases, on the other, purposefully place the referential integrity and lookups
into the problem domain - that is the problem they are designed to solve. An RDBMS presumes
you can design somehtign more efficient for your specific circumstances than the JVM does
(you trust its ability to do object lookups in the heap is sufficiently efficient). As an
RDBMS has a much larger heap equivalent, it is designed to not operate under that assumption
(mostly). So, in an RDBMS the concept of specific foreign keys exists to maintain the referential
integrity.
  		</p>
  		<p>
  		In crossing the object to relational entity barrier there is a mismatch between the referential
integrity implementations. Java programers do not want to have to maintain both object referential
integrity and key referential integrity analogous to
  		</p>
  		<source><![CDATA[
  {
      Foo parent = new SomeFooType();
      Foo child = new SomeOtherFooType();
      parent.addChild(child);
      child.setParentId(parent.getId());
  }
  		]]></source>
  		<p>
  		This is double the work required - you set up the object relationship, then set up the
key relationship.
  		</p>
  		<p>
  		OJB can provide transparent key relationship maintenance behind the scenes via anonymous
access fields. As object relationships change, the relationships will be propogated into the
key values without the Java object ever being aware of a relational key being in use.
  		</p>
  	</subsection>
  </section>
  <section name="Using Anonymous Keys">
  	<subsection name="The Code">
  		<p>
  		Take the following classes designed to model a particular problem domain. They may do
it reasonably well, or may not. Presume they model it perfectly well for the problem being
solved.
  		</p>
  		<source><![CDATA[
  public class Desk
  {
      private Finish finish;
  
      /** Contains Thing instances */
      private Set drawers;
  
      private int numberOfLegs;
  
      public Set getDrawers()              { return this.drawers; }
  
      public int getNumberOfLegs()         { return this.numberOfLegs; }
      public void setNumberOfLegs(int num) { this.numberOfLegs = num; }
  
      public Finish getFinish              { return this.finish; }
      public void setFinish(Finish finish) { this.finish = finish }
  }
      
  public class Drawer
  {
      /** Contains anything */
      private Collection stuffInDrawer;
  
      public Collection getStuffInDrawer() { return this.stuffInDrawer; }
  }
  	
  public class Finish
  {
      private String wood;
      private String color;
  
      public String getWood()              { return this.wood; }
      public void setWood(String nom)      { this.wood = wood; }
  
      public String getColor()             { return this.color; }
      public void setColor(String color)   { this.color = color; }
  }
      
  public class Thing
  {
      private String name;
  
      public String getName()              { return this.name; }
      public String setName(String name)   { this.name = name; }
  }
  		]]></source>
  		<p>
  		A Desk will typically reference multiple drawers and one finish.
  		</p>
  	</subsection>
  	<subsection name="The Database">
  		<p>
  		When we need to store our instances in a database we use a fairly typical table per class
persistance model.
  		</p>
  		<source><![CDATA[
  CREATE TABLE desk
  (
      id          INTEGER PRIMARY KEY,
      num_legs    INTEGER,
  );
      
  CREATE TABLE drawer
  (
      id          INTEGER PRIMARY KEY,
      desk_id     INTEGER FOREIGN KEY REFERENCES desk(id)
  );
      
  CREATE TABLE thing
  (
      id          INTEGER PRIMARY KEY,
      name        VARCHAR(255),
      drawer_id   INTEGER FOREIGN KEY REFERENCES drawer(id)
  );
      
  CREATE TABLE finish
  (
      id          INTEGER PRIMARY KEY,
      wood        VARCHAR(255),
      color       VARCHAR(255),
      desk_id     INTEGER FOREIGN KEY REFERENCES desk(id)
  );
  		]]></source>
          <p>
          At the database level the possible relationships need to be explicitely defined
by teh foreign key constraints. These model all the possible object relationships according
to the domain model (until generics enter the Java language for the collections API, this
is technically untrue for the classes used here).
          </p>
  	</subsection>
  	<subsection name="The Repository Configuration">
          <p>
              When we go to map the classes to the database, it is almost a one-to-one property
to field mapping. The exception here is the primary key on each entity. This is meaningless
information in Java, so we would like to keep it out of the object model. Anonymous access
keys allow us to do that.
          </p>
          <p>
              The repository.xml must know about the database columns used for referential
integrity, but OJB can maintain the foreign key relationships behind the scenes - freeing
the developer to focus on more accurate modeling of her objects to the problem, instead of
the the persistance mechanism. Doing this is also very simple - in the repository.xml file
mark the field descriptors with a <code>access="anonymous"</code> attribute. 
          </p>
          <source><![CDATA[
  <class-descriptor
      class="Desk"
      table="desk">
      
      <field-descriptor
          name="id"
          column="id"
          jdbc-type="INTEGER"
          primarykey="true"
          autoincrement="true"
          access="anonymous"
          />
      <field-descriptor
          name="numberOfLegs"
          column="num_legs"
          jdbc-type="INTEGER"
          />
      <collection-descriptor
          name="drawers"
          element-class-ref="Drawer"
          >
          <inverse-foreignkey field-ref="deskId"/>
      </collection-descriptor>
      
      <reference-descriptor
          name="finish"
          class-ref="Finish">
              <foreignkey field-ref="deskId""/>
      </reference-descriptor>
  </class-descriptor>
  
  <class-descriptor
      class="Finish"
      table="finish">
      
      <field-descriptor
          name="id"
          column="id"
          jdbc-type="INTEGER"
          primarykey="true"
          autoincrement="true"
          access="anonymous"
          />
      <field-descriptor
          name="wood"
          column="wood"
          jdbc-type="VARCHAR"
          size="255"
          />
     <field-descriptor
          name="color"
          column="color"
          jdbc-type="VARCHAR"
          size="255"
          />
      <field-descriptor
          name="deskId"
          column="desk_id"
          jdbc-type="INTEGER"
          />
  </class-descriptor>
  
  <class-descriptor
      class="Drawer"
      table="drawer">
      
      <field-descriptor
          name="id"
          column="id"
          jdbc-type="INTEGER"
          primarykey="true"
          autoincrement="true"
          access="anonymous"
          />
      <field-descriptor
          name="deskId"
          column="desk_id"
          jdbc-type="INTEGER"
          access="anonymous"
          />
      <collection-descriptor
          name="stuffInDrawer"
          element-class-ref="Thing"
          >
          <inverse-foreignkey field-ref="drawerId"/>
      </collection-descriptor>
  </class-descriptor>
  
  <class-descriptor
      class="Thing"
      table="thing">
      
      <field-descriptor
          name="id"
          column="id"
          jdbc-type="INTEGER"
          primarykey="true"
          autoincrement="true"
          access="anonymous"
          />
      <field-descriptor
          name="name"
          column="name"
          jdbc-type="VARCHAR"
          size="255"
          />
      <field-descriptor
          name="drawerId"
          column="drawer_id"
          jdbc-type="INTEGER"
          access="anonymous"
          />
  </class-descriptor>
          ]]></source>
          <p>
          Look first at the class descriptor for the Thing class. Notice the field-descriptor
with the name attribute "drawerId". This field is labeled as anonymous access. Because it
is anonymous access OJB will not attempt to assign the value here to a "drawerId" field or
property on the Thing class. Normally the name attribute is used as the Java name for the
attribute, in this case it is not. The name is still required because it is used as an indicated
for references to this anonymous field.
          </p>
          <p>
          In the field descriptor for Drawer, look at the collection descriptor with the name
"stuffInDrawer". This collection descriptor references a foreign key with the <code>field-ref="drawerId"</code>.
This reference is to the anonymous field descriptor in the Thing descriptor. The field-ref
matches to the name in the descriptor whether or not the name also maps to the Java attribute
name. This dual use of <code>name</code> can be confusing - be careful.
          </p>
          <p>
          The same type mapping that is used for the collection descriptor in the Drawer descriptor
is also used for the 1:1 reference descriptor in the Desk descriptor.
          </p>
  	</subsection>
      <subsection name="Benefits and Drawbacks">
          <p>
          There are both benefits and drawbacks to using anonymous field references for maintaining
referential integrity between Java objects and database relations. The most immediate benefit
is avoiding semantic code duplication. The second major benefit is avoiding cluttering class
definitions with persistance mechanism artifacts. In a well layered application, the persistance
mechanism will not really need to be so obvious in the object model implementation. Anonymous
fields helpt o achieve this - thereby making persistence mechanisms more flexible. Moving
to a different one becomes easier.
          </p>
          <p>
          There is an indirect benefit to populating the various id type keys though, particularly
in web based applications where yet another layer boundary must be crossed - to an html or
html-form format where object references are again lost. If unique ids are not part of a class,
they will wind up being regenerated at the object level for crossing to the next layer. While
this might be a better method to a layer purist, it is considerably less efficient.
          </p>
      </subsection>
  </section>
  </body>
  </document>
  
  
  
  

Mime
View raw message