-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: multiple inheritance using interfaces
PostPosted: Mon Mar 27, 2006 5:58 am 
Beginner
Beginner

Joined: Tue Apr 05, 2005 12:09 pm
Posts: 48
Location: Slovakia (SK), Košice (KE)
hello

how would be the best way to map multiple inheritance using interfaces in hibernate? i've read many discussions (here and googled) but with only partial answers i can't use to create a working example.

Imagine:
Code:
interface FooAble {
    get/setFooProp1
    get/setFooProp2
}
interface BarAble {
    get/setBarProp1
    get/setBarProp2
}
class Poor {
    get/setPoorProp1
    get/setPoorProp2
}
class FooMaster implements FooAble {
    get/setFooProp1
    get/setFooProp2
    get/setFooMasterProp1
    get/setFooMasterProp2
}
class BarMaster implements BarAble {
    get/setBarProp1
    get/setBarProp2
    get/setBarMasterProp1
    get/setBarMasterProp2
}
class FooBarMaster implements FooAble, BarAble {
    get/setFooProp1
    get/setFooProp2
    get/setBarProp1
    get/setBarProp2
    get/setFooBarMasterProp1
    get/setFooBarMasterProp2
}


In the DB there would be these tables:
FOOABLE, BARABLE, POOR, FOOMASTER, BARMASTER, FOOBARMASTER

If I needed to fetch a FooMaster instance, the hibernate would do:
SELECT ... FROM FOOABLE JOIN FOOMASTER

If I needed to fetch a FooBarMaster instance, the hibernate would do:
SELECT ... FROM FOOABLE JOIN BARABLE JOIN FOOBARMASTER

Is something like that possible in Hibernate 3? If not, what would be the bes approach? (please example with .hbm.xml mappings too). I think many hibernate users would like to see clear answer how to best solve this problem (please put it then to the FAQ too).

Many thanks in advance.

_________________
Martin


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 27, 2006 10:00 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Are you absolutely certain that inheritance is the way to go? In pretty much all cases, it's not. Delegation is the correct solution. Give me a concrete example and I'll convince you to use Delegation. Consider the "is-a" and "has-a" relationships when thinking about your schema. Also don't foget that hibernate mappings that model the delegation pattern are much easier than ones that model inheritance.

If any of these are true, you should be using delegation:
- An object can change type (from a FooMaster to a FooBarMaster)
- More similar types might be added in the future (sure Foo, Bar and FooBar isn't too complex.. but add in Snaf and now you've got Foo, Bar, Snaf, FooBar, FooSnaf, BarSnaf and FooBarSnaf. Try adding in one more level...)
- You're using inheritance "because it's nice"
- You're using inheritance to take advantage of fields, rather than because the thing that's inheriting has an is-a relationship with the thing that's being inherited (e.g. having CompanyDepartment extend Set just because it has a Set of people in it.. a CompanyDepartment most definitely is NOT a kind of Set).


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 28, 2006 3:11 am 
Beginner
Beginner

Joined: Tue Apr 05, 2005 12:09 pm
Posts: 48
Location: Slovakia (SK), Košice (KE)
Thanks for reply

Quote:
Are you absolutely certain that inheritance is the way to go?

No, I am not :-/

Here is my mapping. It maps several WidgetTypes (GUI Widgets). Now it is some "mixture" of mappings. As you can see, many widgets have the same groups of properties as other. Therefore I define an interface for each significant group of properties, but only in the java code, not in mapping (i cant) (example of one interface is below mapping). I would much appreciate if you helped me to refactor my mapping which I find now awkward. My requests:

1. my java code is often dependent on the widget type. therefore i often use constructions as - if (widgetType instanceof IWidgetTypeTextual) { ... retype ... }. I know it's not very correct. Moreover I use visitor design pattern where I can, unfortunately I can't use it for interfaces.
2. in the current mapping is one dumb table KFE_WIDGET_TYPE_ABSTRACT i'd like to get rid of

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="some.package.model">
   <class name="WidgetType" table="KFE_WIDGET_TYPE_ABSTRACT" abstract="true" lazy="false">
      <id name="id" unsaved-value="null" column="WIDGET_ID" node="@id">
         <generator class="foreign">
            <param name="property">widget</param>
         </generator>
      </id>
      
      <one-to-one name="widget" class="WidgetImpl" constrained="true" embed-xml="false" node="@refId" />
      
      <joined-subclass name="WidgetTypePicture" table="KFE_WIDGET_TYPE_PICTURE" lazy="false">
         <key column="WIDGET_ID" />
         <property name="filename" column="FILENAME" not-null="true" node="filename/@filename" />
      </joined-subclass>

      <joined-subclass name="WidgetTypeSeparationLine" table="KFE_WIDGET_TYPE_SEPLINE" lazy="false">
         <key column="WIDGET_ID" />
      </joined-subclass>

      <joined-subclass name="WidgetTypeSpacer" table="KFE_WIDGET_TYPE_SPACER" lazy="false">
         <key column="WIDGET_ID" />
         <property name="width" column="WIDTH" not-null="false" />
         <property name="height" column="HEIGHT" not-null="false" />
      </joined-subclass>

      <joined-subclass name="WidgetTypeUsingColumn" table="KFE_TABLE_COLUMN" abstract="true" lazy="false">
         <key column="WIDGET_ID" />
         <property name="name" column="COLUMN_NAME" length="50" not-null="true" />
         <property name="defaultValue" column="DEFAULT_VALUE" not-null="false" />
         <property name="primaryKey" column="PRIMARY_KEY_YN" not-null="true" />
         <property name="notNull" column="NOTNULL_YN" not-null="true" />
         <property name="forceDefault" column="FORCE_DEFAULT" not-null="true" />
         <property name="importable" column="IMPORTABLE" not-null="true" />
         
         <joined-subclass name="WidgetTypeText" table="KFE_WIDGET_TYPE_INPUTTEXT" lazy="false">
            <key column="WIDGET_ID" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="deletable" column="DELETABLE" not-null="true" />
            <property name="readonly" column="READONLY" not-null="true" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
         </joined-subclass>
   
         <joined-subclass name="WidgetTypeTextarea" table="KFE_WIDGET_TYPE_INPUTTEXTAREA" lazy="false">
            <key column="WIDGET_ID" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="height" column="HEIGHT" not-null="true" />
            <property name="deletable" column="DELETABLE" not-null="true" />
            <property name="readonly" column="READONLY" not-null="true" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
         </joined-subclass>

         <joined-subclass name="WidgetTypeCheckbox" table="KFE_WIDGET_TYPE_CHECKBOX" lazy="false">
            <key column="WIDGET_ID" />
            <property name="checkedValue" column="CHECKED_VALUE" not-null="true" />
            <property name="uncheckedValue" column="UNCHECKED_VALUE" not-null="true" />
            <property name="readonly" column="READONLY" not-null="true" />
         </joined-subclass>
   
         <joined-subclass name="WidgetTypeDropdown" table="KFE_WIDGET_TYPE_DROPDOWN" lazy="false">
            <key column="WIDGET_ID" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="strict" column="STRICT" not-null="true" />
            <property name="deletable" column="DELETABLE" not-null="true" />
            <property name="readonly" column="READONLY" not-null="true" />
            <property name="whereCondition" column="WHERE_CONDITION" not-null="false" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <property name="distinct" column="DISTINCT_FLAG" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
         </joined-subclass>

         <joined-subclass name="WidgetTypeDropdownEx" table="KFE_WIDGET_TYPE_DROPDOWN_EX" lazy="false">
            <key column="WIDGET_ID" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="lookupSchema" column="LOOKUP_SCHEMA" not-null="false" />
            <property name="lookupTable" column="LOOKUP_TABLE" not-null="true" />
            <property name="lookupTableKey" column="LOOKUP_TABLE_KEY" not-null="false" />
            <property name="lookupTableValue" column="LOOKUP_TABLE_VALUE" not-null="true" />
            <property name="strict" column="STRICT" not-null="true" />
            <property name="deletable" column="DELETABLE" not-null="true" />
            <property name="readonly" column="READONLY" not-null="true" />
            <property name="whereCondition" column="WHERE_CONDITION" not-null="false" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <property name="distinct" column="DISTINCT_FLAG" not-null="true" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
         </joined-subclass>

         <joined-subclass name="WidgetTypeMultiselect" table="KFE_WIDGET_TYPE_MULTISELECT" lazy="false">
            <key column="WIDGET_ID" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="format" column="FORMAT" not-null="true" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="distinct" column="DISTINCT_FLAG" not-null="true" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
         </joined-subclass>

         <joined-subclass name="WidgetTypeMultiselectEx" table="KFE_WIDGET_TYPE_MULTISELECT_EX" lazy="false">
            <key column="WIDGET_ID" />
            <property name="lookupSchema" column="LOOKUP_SCHEMA" not-null="false" />
            <property name="lookupTable" column="LOOKUP_TABLE" not-null="true" />
            <property name="lookupTableKey" column="LOOKUP_TABLE_KEY" not-null="false" />
            <property name="lookupTableValue" column="LOOKUP_TABLE_VALUE" not-null="true" />
            <property name="width" column="WIDTH" not-null="true" />
            <property name="distinct" column="DISTINCT_FLAG" not-null="true" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
         </joined-subclass>

         <!-- READONLY WIDGETS -->
         
         <joined-subclass name="WidgetTypeLabel" table="KFE_WIDGET_TYPE_LABEL" lazy="false">
            <key column="WIDGET_ID" />
            <property name="constraint" column="CONSTRAINT" not-null="false" />
            <property name="format" column="FORMAT" not-null="true" />
            <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
            <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
         </joined-subclass>

         <joined-subclass name="WidgetTypeDynapic" table="KFE_WIDGET_TYPE_DYNAPIC" lazy="false">
            <key column="WIDGET_ID" />
            <property name="urlPrefix" column="URL_PREFIX" not-null="false" />
         </joined-subclass>
      </joined-subclass>

   </class>
</hibernate-mapping>


Example of interface
Code:
public interface IWidgetTypeTextual {
   public String getConstraint();
   public void setConstraint(String constraint);
   public String getFormat();
   public void setFormat(String format);
   public VisualDefinition getVisualDefinition();
   public void setVisualDefinition(VisualDefinition visualDefinition);
   public WidgetSampleFormatText getSampleFormatText();
   public void setSampleFormatText(WidgetSampleFormatText sampleFormatText);
}


Thank you in advance[/quote]

_________________
Martin


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 28, 2006 5:57 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I don't think that any of those mappings should be related. I'm not sure how WidgetImpl fits into all of this, but the various WidgetType classes should all be "top-level" mappings, not joined-subclasses. You can implement the inheritance/interfacing in java and leave it out of the mapping. For widgets that share groups of properties, assuming that you want to normalize your tables and split your widgets across several tables, then you delegate from the "real" WidgetType subclass to the nested AbstractWidgetType. Here's a brief example:
Code:
<class name="WidgetColumnProperties" ...>
  ...
  <property name="name" column="COLUMN_NAME" length="50" not-null="true" />
  <property name="defaultValue" column="DEFAULT_VALUE" not-null="false" />
  <property name="primaryKey" column="PRIMARY_KEY_YN" not-null="true" />
  <property name="notNull" column="NOTNULL_YN" not-null="true" />
  <property name="forceDefault" column="FORCE_DEFAULT" not-null="true" />
  <property name="importable" column="IMPORTABLE" not-null="true" />
</class>

<class name="WidgetTypeText" ...>
  ...
  <one-to-one name="ColumnProperties" class="WidgetColumnProperties"/>

  <property name="width" column="WIDTH" not-null="true" />
  <property name="deletable" column="DELETABLE" not-null="true" />
  <property name="readonly" column="READONLY" not-null="true" />
  <property name="constraint" column="CONSTRAINT" not-null="false" />
  <property name="format" column="FORMAT" not-null="true" />
  <one-to-one name="sampleFormatText" class="WidgetSampleFormatText" cascade="all" />
  <many-to-one unique="true" name="visualDefinition" class="VisualDefinition" cascade="all" column="VISUAL_DEFINITION_ID" not-null="true" />
  ...
</class>
Your java code will be slightly larger, because now your WidgetTypeText class, which implements the WidgetTypeUsingColumn interface and the WidgetTypeTextInterface, has to implement things like
Code:
public boolean getPrimaryKey() { return getColumnProperties().getPrimaryKey(); }
But the mapping is clean and the model is infinitely extensible.. you don't have to rejig any relationships later if you decide to add in a WidgetTypeVariableWitdhColumn between WidgetTypeUsingColumn and WidgetTypeText: just add another interface to the WidgetTypeText class and another one-to-one mapping in the mapping file.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.