cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Cayenne Documentation > Modeling Inheritance
Date Sat, 10 Jul 2010 08:17:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/1/_/styles/combined.css?spaceKey=CAYDOC&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CAYDOC/Modeling+Inheritance">Modeling
Inheritance</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~andrus">Andrus
Adamchik</a>
    </h4>
        <br/>
                         <h4>Changes (0)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h2><a name="ModelingInheritance-WhyUseInheritance%3F"></a>Why Use
Inheritance?</h2>

<p>Inheritance is a powerful OO feature and can significantly simplify your code, but
it does take a little time to fully understand how it works within an ORM framework like Cayenne.
We will use a simple example from school database to illustrate the concepts: a Person could
be either a Student or a Teacher and so in Java you'd want to express these as a Person class
with Student and Tutor as two subclasses. The Java class structure (the object entities) looks
roughly like this:</p>


<p><span class="image-wrap" style=""><img src="/confluence/download/attachments/55796/inheritance-example.png?version=1&amp;modificationDate=1180613216000"
style="border: 0px solid black" /></span></p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">abstract</span>
class Person <span class="code-keyword">extends</span> PersistentObject {}
<span class="code-keyword">public</span> class Teacher <span class="code-keyword">extends</span>
Person {}
<span class="code-keyword">public</span> class Student <span class="code-keyword">extends</span>
Person {}
</pre>
</div></div>

<p>Some possibilities are immediately obvious: you may wish to write a messaging system
which sends emails to both Students and Teachers. Rather than deal with the two classes separately,
now you can move the emailAddress attribute to the Person superclass. Your messaging framework
can now work with Person, irrespective if they are students, tutors or any other subclasss
of Person. Or perhaps you want to be able to link book loans to both Students and Teachers.
You can do this by moving the relationship with book loans into the Person superclass.</p>

<h2><a name="ModelingInheritance-AbstractorConcreteSuperclass"></a>Abstract
or Concrete Superclass</h2>

<p>Notice that in the example above, Person is an abstract class. That is, you cannot
commit a person who is neither a Student nor a Teacher. But sometimes it is useful to make
the superclass concrete and not abstract. This allows you to store a Person without yet giving
them attributes from either subclass. Perhaps they are simply a person for whom we wish to
store some contact information. Maybe later on they will become a Student and we will add
those attributes. Because Java does not have multiple inheritance, it is not possible for
a person to be a Student and a Teacher at the same time. Interfaces are probably a good way
to address that type of model and will be discussed later.</p>

<h2><a name="ModelingInheritance-Roles"></a>Roles</h2>

<p>Sometimes you want a Person to be a Student or a Teacher or both at the same time.
Sometimes this is described as the Person entity having Roles 'person' and 'teacher'. Cayenne
isn't going to help you much since Java inheritance cannot cope with this concept. Nothing
on this page applies to you. Sorry about that. Instead, you'll need to create your own one-to-one
relations between Person, Teacher and Student, and then manage the roles in your own code.</p>


<h2><a name="ModelingInheritance-InheritanceandORM"></a>Inheritance and
ORM</h2>

<p>There are three ways to implement inheritance in the database. Different terms are
used sometimes by different frameworks to describe the implementations of inheritance, but
they refer to the same common concepts:</p>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'>Cayenne</th>
<th class='confluenceTh'>Hibernate</th>
<th class='confluenceTh'>JPA</th>
</tr>
<tr>
<td class='confluenceTd'>Single table</td>
<td class='confluenceTd'>table-per-class-hierarchy</td>
<td class='confluenceTd'>single table</td>
</tr>
<tr>
<td class='confluenceTd'>Vertical</td>
<td class='confluenceTd'>table-per-subclass</td>
<td class='confluenceTd'>joined</td>
</tr>
<tr>
<td class='confluenceTd'>Horizontal <em>(currently unsupported)</em></td>
<td class='confluenceTd'>table-per-concrete-class</td>
<td class='confluenceTd'>table per class</td>
</tr>
</tbody></table>
</div>


<p>Cayenne supports two of them (single table and vertical), as described in the following
chapters. Here we will provide a general overview of these types of mappings.</p>

<p><span class="image-wrap" style=""><img src="/confluence/download/attachments/55796/inheritance-overview.png?version=1&amp;modificationDate=1180613226000"
style="border: 0px solid black" /></span></p>

<h3><a name="ModelingInheritance-SingleTableInheritance"></a>Single Table
Inheritance</h3>

<p>One database table or view (dbEntity) is used for all the subclasses and the superclass.
So Person, Student and Teacher are all mapped against the one dbEntity. If an attribute appears
in Student but not in Teacher (for example the hasScholarship attribute) then that column
in the database is set to NULL for all Teachers committed. Naturally, the columns found only
in the subclasses cannot be restricted to 'NOT NULL' in the database.</p>

<p>This type of inheritance works well when there are only a few attributes which are
different between the two subclasses and you don't mind having all the records from the subclasses
combined in one table.</p>

<p>In Cayenne modeler you create this type of inheritance by pointing the superclass
and subclass both to the same dbEntity. You must also define a class designator column which
allows Cayenne to determine which subclass any particular record in the table belongs to.
This column can only be NULL if the superclass is not abstract.</p>

<p>Superclass: abstract or concrete<br/>
Class designator column: required<br/>
Primary key: single column shared by superclass and subclass</p>

<p>Single table inheritance mapping in Cayenne is described <a href="/confluence/display/CAYDOC/Modeling+Single+Table+Inheritance"
title="Modeling Single Table Inheritance">here</a>.</p>

<h3><a name="ModelingInheritance-Vertical%28JoinedTable%29Inheritance"></a>Vertical
(Joined Table) Inheritance</h3>

<p>This approach requires one table per subclass plus one table for the superclass.
All attributes found in the superclass are stored in this additional table. This is particularly
useful when you have lots of common attributes or relations to other entities. Perhaps Person
is subclassed by Student, Teacher, Parent, AdminStaff, Visitor and Applicant. But all these
entities are allowed to borrow books from the library. Now, rather than creating 6 relationships
between each of these tables to the Loan table, you can create a single relationship between
Person and Loan.</p>

<p>Superclass: abstract or concrete<br/>
Class designator column: required<br/>
Primary key: in superclass. Copied into subclass to form the one-to-one join.</p>

<p>Vertical inheritance mapping in Cayenne is described <a href="/confluence/display/CAYDOC/Modeling+Vertical+Inheritance"
title="Modeling Vertical Inheritance">here</a>.</p>

<h3><a name="ModelingInheritance-Horizontal%28TablePerClass%29Inheritance"></a>Horizontal
(Table Per Class) Inheritance</h3>

<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>As of this writing Cayenne does
not support horizontal inheritance, but it may in the future.</td></tr></table></div>

<p>Here you will need one table per subclass. So your database will have Student and
Teacher tables. Any attributes in the Person object entity will need to be present in both
the database tables.</p>

<p>This type of inheritance is best used when there are few attributes which are found
in the superclass. Because the superclass is abstract you cannot have a relationship to other
entities. For instance if you want to relate both Students and Teachers to library Books borrowed,
then it would be useful to have a single relationship from Person to Books. That is possible
in vertical inheritance.</p>

<p>Normally if you use horizontal inheritance you will set your superclass to be abstract,
but this is not a requirement. If it is a concrete class, then it is important to remember
that you cannot create and commit to the database object entities of this superclass, since
Cayenne would not know which table to add the record to. However you are able to create and
commit Students and Teachers, fetch and edit them as concrete Person objects and then commit
them back the database as Person objects, since Cayenne now 'knows' what subclass they belong
to.</p>

<p>Superclass: abstract or concrete (usually abstract)<br/>
Class designator column: not required<br/>
Primary key: in each subclass (unique across all subclasses)</p>


<h2><a name="ModelingInheritance-Interfaces"></a>Interfaces</h2>

<p>Sometimes you don't need inheritance but rather you want Cayenne to give you a simple
way to define an interface for your classes. The regular Student and Teacher classes both
need to implement emailAddress attributes so that you have a consistent way to access that
attribute.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">public</span> <span class="code-keyword">interface</span>
Address {
	<span class="code-keyword">public</span> <span class="code-object">String</span>
getEmailAddress();
}
<span class="code-keyword">public</span> class Teacher <span class="code-keyword">extends</span>
PersistentObject <span class="code-keyword">implements</span> Address {}
<span class="code-keyword">public</span> class Student <span class="code-keyword">extends</span>
PersistentObject <span class="code-keyword">implements</span> Address {}
</pre>
</div></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CAYDOC/Modeling+Inheritance">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=55796&revisedVersion=10&originalVersion=9">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CAYDOC/Modeling+Inheritance?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message