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 Tue, 27 Jul 2010 11:55: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 (40)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2.
Why Use Inheritance? <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h2.
Overview <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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&#39;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: <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Inheritance
is a familiar and a very useful concept to any Java developer. There are three common ways
of mapping it to a relational schema. In Cayenne we are calling them &quot;single table&quot;,
&quot;vertical&quot; and &quot;horizontal&quot;. Other ORM frameworks may
use different terms for those (e.g. in JPA &quot;single table&quot; is called &quot;single
table per class&quot;, &quot;vertical&quot; - &quot;joined subclass&quot;,
and &quot;horizontal&quot; - &quot;table per concrete class&quot;, still they
are referring to the same types of mapping). The picture below is a high-level representation
of these three strategies.  <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{note}As
of this writing Cayenne does not support horizontal inheritance. It may in the future.{note}
<br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">!inheritance-example.png!</span>
<span class="diff-added-words"style="background-color: #dfd;">!inheritance-overview.png!</span>
<br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">{code}
<br>public abstract class Person extends PersistentObject {} <br>public class
Teacher extends Person {} <br>public class Student extends Person {} <br>{code}
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">We&#39;ll
discuss them in general terms in this chapter and provide Cayenne-specific details in dedicated
chapters. Here we should mention that ORM inheritance should not be overused and there is
some performance penalty associated with it. Often composition is a better way to model a
particular problem. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2.
Abstract or Concrete Superclass <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h2.
Types of Inheritance <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2.
Roles <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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 &#39;person&#39; and &#39;teacher&#39;.
Cayenne isn&#39;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&#39;ll need
to create your own one-to-one relations between Person, Teacher and Student, and then manage
the roles in your own code. <br> <br> <br>h2. Inheritance and ORM <br>
<br>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: <br> <br>||Cayenne||Hibernate||JPA|| <br>|Single
table|table-per-class-hierarchy|single table| <br>|Vertical|table-per-subclass|joined|
<br>|Horizontal _(currently unsupported)_|table-per-concrete-class|table per class|
<br> <br>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.
<br> <br>!inheritance-overview.png! <br> <br></td></tr>
            <tr><td class="diff-unchanged" >h3. Single Table Inheritance <br>
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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 &#39;NOT NULL&#39; in the database. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">One
database table is used to map all the subclasses and the superclass. So Superclass, Subclass1
and Subclass2 are all mapped to a single table. Such table has to contain columns to store
the attributes of an entire class hierarchy. One or more columns are used as &quot;discriminator
columns&quot; that tell Cayenne what type of record is stored in a given row. Single table
inheritance provides good select performance, however the storage of data is not optimized.
<br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">This
type of inheritance works well when there are only a few attributes which are different between
the two subclasses and you don&#39;t mind having all the records from the subclasses combined
in one table. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
Vertical Inheritance <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">One
database table is used to map superclass columns, additionally one table per subclass is joined
via a 1..1 relationship with the superclass table. So &quot;Superclass&quot; will
have its own table, and extra attributes found in Subclass1 and Subclass2 will be stored in
two separate tables joined with the superclass table. Discriminator columns are required for
the same reason as with Single Table Inheritance. Vertical inheritance optimizes the data
storage and provides a view of data very close to that of the Java classes. However that comes
at a cost of doing one or more joins in every query, which may not scale into deep and wide
inheritance hierarchies. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Superclass:
abstract or concrete <br>Class designator column: required <br>Primary key: single
column shared by superclass and subclass <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
Horizontal Inheritance <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Single
table inheritance mapping in Cayenne is described [here|Modeling Single Table Inheritance].
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">_(Currently
unsupported by Cayenne)_ <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h3.
Vertical (Joined Table) Inheritance <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">With
horizontal inheritance a superclass is usually abstract, and each subclass is mapped to its
own independent database table. In our example &quot;Superclass&quot; will not have
a table, all attributes, including inherited, of Subclass1 and Subclass2 will be stored in
separate tables. Discriminator column is not required. Select performance of the horizontal
inheritance mapping is not very good, as a union or a separate query per subclass is used
to get the data. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h3.
Comparing ORM Inheritance Types <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Superclass:
abstract or concrete <br>Class designator column: required <br>Primary key: in
superclass. Copied into subclass to form the one-to-one join. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">||Inheritance
Type||Discriminator Column||Primary Key||Pros and Cons|| <br>|[Single Table|Modeling
Single Table Inheritance]|required|shared by superclasses and subclasses|good select performance
(no joins). Storage is not optimized.| <br>|[Vertical|Modeling Vertical Inheritance]|required|propagated
from superclass to subclasses via a join|optimized data storage and a data view close to object
oriented one. Adds (N - 1) joins to select, where N is the number of classes in the hierarchy|
<br>|Horizontal _(unsupported)_|not needed|independent in each table|selects normally
require a UNION across tables|  <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Vertical
inheritance mapping in Cayenne is described [here|Modeling Vertical Inheritance]. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h2.
Mapping Inheritance in Cayenne <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h3.
Horizontal (Table Per Class) Inheritance <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Now
that we discussed various types of inheritance, it should be noted that the type of inheritance
_is not specified explicitly_. Instead Cayenne guesses it from the mapping. This allows for
mixing multiple types in a single hierarchy. The following chapters will explain how the mapping
is done in each case: <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">{note}As
of this writing Cayenne does not support horizontal inheritance, but it may in the future.{note}
<br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> <span class="diff-added-words"style="background-color: #dfd;">{excerpt}</span>
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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.
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">#
[Modeling Single Table Inheritance] <br># [Modeling Vertical Inheritance] <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">
</span> <span class="diff-added-words"style="background-color: #dfd;">{excerpt}</span>
<br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">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. <br> <br>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
&#39;knows&#39; what subclass they belong to. <br> <br>Superclass: abstract
or concrete (usually abstract) <br>Class designator column: not required <br>Primary
key: in each subclass (unique across all subclasses) <br> <br> <br>h2. Interfaces
<br> <br>Sometimes you don&#39;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. <br> <br>{code} <br>public interface Address
{ <br>	public String getEmailAddress(); <br>} <br>public class Teacher extends
PersistentObject implements Address {} <br>public class Student extends PersistentObject
implements Address {} <br>{code} <br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h2><a name="ModelingInheritance-Overview"></a>Overview</h2>

<p>Inheritance is a familiar and a very useful concept to any Java developer. There
are three common ways of mapping it to a relational schema. In Cayenne we are calling them
"single table", "vertical" and "horizontal". Other ORM frameworks may use different terms
for those (e.g. in JPA "single table" is called "single table per class", "vertical" - "joined
subclass", and "horizontal" - "table per concrete class", still they are referring to the
same types of mapping). The picture below is a high-level representation of these three strategies.
</p>

<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. It may in the future.</td></tr></table></div>

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

<p>We'll discuss them in general terms in this chapter and provide Cayenne-specific
details in dedicated chapters. Here we should mention that ORM inheritance should not be overused
and there is some performance penalty associated with it. Often composition is a better way
to model a particular problem.</p>


<h2><a name="ModelingInheritance-TypesofInheritance"></a>Types of Inheritance</h2>



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

<p>One database table is used to map all the subclasses and the superclass. So Superclass,
Subclass1 and Subclass2 are all mapped to a single table. Such table has to contain columns
to store the attributes of an entire class hierarchy. One or more columns are used as "discriminator
columns" that tell Cayenne what type of record is stored in a given row. Single table inheritance
provides good select performance, however the storage of data is not optimized.</p>

<h3><a name="ModelingInheritance-VerticalInheritance"></a>Vertical Inheritance</h3>

<p>One database table is used to map superclass columns, additionally one table per
subclass is joined via a 1..1 relationship with the superclass table. So "Superclass" will
have its own table, and extra attributes found in Subclass1 and Subclass2 will be stored in
two separate tables joined with the superclass table. Discriminator columns are required for
the same reason as with Single Table Inheritance. Vertical inheritance optimizes the data
storage and provides a view of data very close to that of the Java classes. However that comes
at a cost of doing one or more joins in every query, which may not scale into deep and wide
inheritance hierarchies.</p>

<h3><a name="ModelingInheritance-HorizontalInheritance"></a>Horizontal Inheritance</h3>

<p><em>(Currently unsupported by Cayenne)</em></p>

<p>With horizontal inheritance a superclass is usually abstract, and each subclass is
mapped to its own independent database table. In our example "Superclass" will not have a
table, all attributes, including inherited, of Subclass1 and Subclass2 will be stored in separate
tables. Discriminator column is not required. Select performance of the horizontal inheritance
mapping is not very good, as a union or a separate query per subclass is used to get the data.</p>

<h3><a name="ModelingInheritance-ComparingORMInheritanceTypes"></a>Comparing
ORM Inheritance Types</h3>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'>Inheritance Type</th>
<th class='confluenceTh'>Discriminator Column</th>
<th class='confluenceTh'>Primary Key</th>
<th class='confluenceTh'>Pros and Cons</th>
</tr>
<tr>
<td class='confluenceTd'><a href="/confluence/display/CAYDOC/Modeling+Single+Table+Inheritance"
title="Modeling Single Table Inheritance">Single Table</a></td>
<td class='confluenceTd'>required</td>
<td class='confluenceTd'>shared by superclasses and subclasses</td>
<td class='confluenceTd'>good select performance (no joins). Storage is not optimized.</td>
</tr>
<tr>
<td class='confluenceTd'><a href="/confluence/display/CAYDOC/Modeling+Vertical+Inheritance"
title="Modeling Vertical Inheritance">Vertical</a></td>
<td class='confluenceTd'>required</td>
<td class='confluenceTd'>propagated from superclass to subclasses via a join</td>
<td class='confluenceTd'>optimized data storage and a data view close to object oriented
one. Adds (N - 1) joins to select, where N is the number of classes in the hierarchy</td>
</tr>
<tr>
<td class='confluenceTd'>Horizontal <em>(unsupported)</em></td>
<td class='confluenceTd'>not needed</td>
<td class='confluenceTd'>independent in each table</td>
<td class='confluenceTd'>selects normally require a UNION across tables</td>
</tr>
</tbody></table>
</div>


<h2><a name="ModelingInheritance-MappingInheritanceinCayenne"></a>Mapping
Inheritance in Cayenne</h2>

<p>Now that we discussed various types of inheritance, it should be noted that the type
of inheritance <em>is not specified explicitly</em>. Instead Cayenne guesses it
from the mapping. This allows for mixing multiple types in a single hierarchy. The following
chapters will explain how the mapping is done in each case:</p>


<ol>
	<li><a href="/confluence/display/CAYDOC/Modeling+Single+Table+Inheritance" title="Modeling
Single Table Inheritance">Modeling Single Table Inheritance</a></li>
	<li><a href="/confluence/display/CAYDOC/Modeling+Vertical+Inheritance" title="Modeling
Vertical Inheritance">Modeling Vertical Inheritance</a></li>
</ol>




    </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=11&originalVersion=10">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