Hibernate Patterns: polymorphic many-to-one

Posted Feb 6, 2008 // 8 comments
Jed:

Recently I found myself in a situation where I needed to define a persistent many-to-one relationship in which the concrete class of the many side could vary. In the past I’d had some issues with class inheritence and Hibernate, which can get sticky because of Hibernate proxies: you can’t always cast the proxies to the desired type. Since I had to find a way to make this work, I decided to give interface inheritence a try. I started with a lightweight interface for a persistent object:


package example;
 
import java.io.Serializable;  

/**
* Note that ID could be more generally defined as Serializable,
* but long worked best in this situation
*/
public interface PersistentLite extends Serializable
{   
   long getId();
   void setId(long id);
}

The relationship is the classic parent-child relationship. This is our parent interface:

package example; 

import java.util.Set; 

/** 
* In practice, the set of children should be restricted to instances of Child,
* but type parameters do not display well in HTML
* so we use the raw type in this example. 
*/
public interface Parent extends PersistentLite
{
   Set getChildren();
   void setChildren(Set children);
}

Here’s the child. In this case, the child also has a couple of different implementations, so it is also defined as an interface:
package example;

public interface Child extends PersistentLite
{
   Parent getParent();
   void setParent(Parent parent);
}

Here are the mappings for parent and child:
<hibernate>
  <class table="parent" name="example.Parent">
    <id name="id"><generator class="native"/></id>
    <discriminator/>       
    <set inverse="true" cascade="all-delete-orphan" name="children">
      <key column="parent"/>
      <one-to-many class="example.Child"/>
    </set>
  </class>
</hibernate>

<hibernate>
  <class table="child" name="example.Child">
    <id name="id"><generator class="native"/></id>
    <discriminator/>
    <many-to-one name="parent"/>
  </class>
</hibernate> 

You would then add implementation classes and mappings, these are representative:
package example;

import java.util.*;

public class ParentImpl implements Parent
{
   private long id;
   private Set children = new TreeSet();
   private String extraData;

   public long getId()
   {
      return id;
   }

   public void setId(long n)
   {
      id = n;
   }
  
   public Set getChildren()
   {
      return children;
   }

   public void setChildren(Set set)
   {
      children = set == null ? new TreeSet() : set;
   }

   public String getExtraData()
   {
      return extraData;
   }

   public void setExtraData(String s)
   {
      extraData = s;
   }
}


package example;
public class ChildImpl implements Child
{
   private long id;
   private Parent parent;
   private String extraData;
  
   public long getId()
   {     
      return id;
   }

   public void setId(long n)
   {
      id = n;
   }

   public Parent getParent()
   {
      return parent;
   }

   public void setParent(Parent p)
   {
       parent = p;
   }

   public String getExtraData()
   {
      return extraData;
   }

   public void setExtraData(String s)
   {
      extraData = s;
   }
}

<hibernate>
  <subclass extends="example.Parent" name="example.ParentImpl">
    <property name="extraData"/>
  </subclass>
</hibernate> 

<hibernate>
  <subclass extends="example.Child" name="example.ChildImpl">
    <property name="extraData"/>
  </subclass>
</hibernate>

The key insight is this: because the interfaces are mapped, Hibernate generates proxies that implement the interface, which eliminates a lot of potential casting problems. By contrast, if you use class inheritance, Hibernate can only generate proxies that implement the interface which the class exposes to Hibernate, and is not necessarily the same as the interface exposed to the system at large. This causes confusion. Moreover, since a lot of casting issues can occur from inside the subclass, via private methods and data, using an interface eliminates a lot potential problems because the interface is well-defined. You could still run into issues when casting, but they are greatly reduced if the interface is properly defined. Finally, using a lightweight interface as the basis of the relationship gives the implementation the flexibility to inherit from a richer base class if desired.

About Jed

Senior Software Engineer Jed Prentice brings more than 15 years of experience developing business applications to Phase2 when he works on our client projects. He is an expert in the field of object-oriented software development, and he ...

more >

Read Jed's Blog

Comments

by Kenneth B. Sizer, II (not verified) on Fri, 04/11/2008 - 16:26

Empty <discriminator> tag?

Perhaps I’m simply too green when it comes to Hibernate, but… Is your Hibernate XML above intended to be complete or are you leaving out details for the sake of clarity?

I have a very practical reason for asking, because I find myself needing to implement something similar to what you discuss above. I have worked with table-per-hierarchy before and with associations, but have never bumped into my current issue:

“There is a many-to-one relationship between WidgetTable and WidgetInfoTable. WidgetTable needs to map to a number of concrete subclasses of a common interface, but WidgetInfoTable contains the discriminator column needed to determine which subclass.”

At any rate, if you could do a public service to the dimwitted by posting a complete example of the Hibernate XML which meets your needs, that might get my oxcart out of the ditch.

—Ken

by Jed on Thu, 04/17/2008 - 12:13

Re: Empty Discriminator Tag

The mapping is complete. The empty discriminator tag simply uses a column named class to store the fully-qualified class name. You can specify various attributes to control these values if you wish, but I have been happy with the defaults.

As far as your issue is concerned, Hibernate figures out which classes to instantiate based on the discriminator column. You don’t have to do anything special assuming you understand how Hibernate deals with polymorphism, but that is another subject and is covered in the manual. If you have specific questions, let me know.

by VB6 (not verified) on Thu, 08/28/2008 - 11:15

Very Cool

This is a very cool example in Java. Do you have any examples in any other languages. I run a Visual Basic Source site and I’d love to have an example like this on it. However, I’m pretty sure it can’t be done :( Just curios if you have any VB experience and if you know if I could develop this.

by Jed on Thu, 08/28/2008 - 13:19

Dunno about VB...

I haven’t done anything with VB in 11+ years (VB4), so I think it is safe to say I don’t know it anymore. But if VB6 has decent OO support, you could probably do something similar.

by Mark Kantor (not verified) on Fri, 08/29/2008 - 10:54

Example of Child Insert

Thanks for this. Can you extend the example to include a child insert? Hibernate documentation says “We also need to add the parent property to the Child class.” http://www.hibernate.org/hib_docs/v3/reference/en/html/example-parentchi... It sounds like an obvious thing to do, but unfortunately no. Does the Child class need a Parent member? Or is this saying that the Child mapping needs a parent property (in addition to the parent many-to-one association). I assume the initial changes to the Child are in the mapping and there may need to be class changes to follow. Assuming I add a parent property to the child what is the type of the parent property? Is this the type of the Parent class or the type of the Parent class’s identifier? And if it is the type of the Parent class then what table column could be associated with it? (A column for the parent identifier maybe?) I am playing around here to see what works. It seems simple and straightforward—yet not crystal clear.
by nate (not verified) on Sat, 04/25/2009 - 00:27

Looks cool

Unfortunately it displays no line breaks to me, just one (very large) line-wrap (Firefox 3.0.9).

by Sascha (not verified) on Fri, 01/29/2010 - 05:44

Mapping for parent and child not visible

Hi Jed,

I was looking a long time for this, but above, there is no text between "Here are the mappings for parent and child:" and "You would then add implementation classes and mappings, these are representative:

Could you add the mapping code, please?

Thanks a lot, Sascha

by prajput (not verified) on Tue, 03/16/2010 - 05:51

parent child mapping in hibernate.

Hi Jed,

I have 5 different classes mapped with Tables. I am getting name of the table Dynamically and then i want to call that particular table.

How can i do it with hibernate and i don't want to have a separate table for any other class say Parent.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
  • Allowed HTML tags: <a> <strong> <code> <p> <img> <ul> <ol> <li> <h2> <h3> <h4> <b> <u> <i>
  • You may insert videos with [video:URL]

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.