-->
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.  [ 6 posts ] 
Author Message
 Post subject: is many to many mapping with subclasses supported?
PostPosted: Mon Dec 20, 2004 2:47 pm 
Regular
Regular

Joined: Mon Sep 20, 2004 8:42 am
Posts: 58
Location: Boston, US
Hibernate version: 2.1.6

I have a ServiceLevel abstract class with two subclasses : BaseServiceLevel and Accessorial.

I have a ServiceGroup entity that has a many-to-many releationship with BaseServiceLevel instances *and* Accessorial instances. In the 'set' mappings for ServiceGroup, I specify two sets- one for BaseServiceLevel's and the other for Accessorial's however what I find is that on running, the ServiceGroup instance does not have the correct set for BaseServiceLevel and Accessorial. All the entries in the link table are mapped to both sets and the discriminator valus specified for the subclass is ignored. Is there a way to model this in Hibernate?

Thanks,
Sanjiv

Mapping documents:

Code:
   <class name="ServiceLevel" table="servicelevel">
      <id name="id" column="servicelevel_id" type="long" unsaved-value="null">
         <generator class="sequence">
            <param name="sequence">servicelevel_sequence</param>
         </generator>
      </id>
      <discriminator column="type"/>

      <property name="name" column="name"/>

      <subclass name="BaseServiceLevel" discriminator-value="0"/>
      <subclass name="Accessorial" discriminator-value="1"/>
   </class>


Code:
   <class name="ServiceGroup" table="servicegroup">
      <id name="id" column="servicegroup_id" type="long" unsaved-value="null">
         <generator class="sequence">
            <param name="sequence">servicegroup_sequence</param>
         </generator>
      </id>
      <property name="name" column="name"/>

      <set name="baseServices" table="servicegroup_content" lazy="true">
         <key column="servicegroup_id"/>
         <many-to-many column="servicelevel_id" class="BaseServiceLevel"/>
      </set>
      <set name="accessorials" table="servicegroup_content" lazy="true" >
         <key column="servicegroup_id"  />
         <many-to-many column="servicelevel_id" class="Accessorial"/>
      </set>
   </class>



Name and version of the database you are using: Oracle 9i

The generated SQL (show_sql=true):
Code:
Hibernate: select servicegro0_.servicegroup_id as serviceg1_0_, servicegro0_.name as name0_ from servicegroup servicegro0_ where servicegro0_.servicegroup_id=?
Hibernate: select baseservic0_.servicegroup_id as serviceg1___, baseservic0_.servicelevel_id as servicel2___, baseservic1_.servicelevel_id as servicel1_0_, baseservic1_.name as name0_, baseservic1_.abbreviation as abbrevia4_0_, baseservic1_.price_unit as price_unit0_ from servicegroup_content baseservic0_, servicelevel baseservic1_ where baseservic0_.servicegroup_id=? and baseservic0_.servicelevel_id=baseservic1_.servicelevel_id
Hibernate: select accessoria0_.servicegroup_id as serviceg1___, accessoria0_.servicelevel_id as servicel2___, accessoria1_.servicelevel_id as servicel1_0_, accessoria1_.name as name0_, accessoria1_.abbreviation as abbrevia4_0_, accessoria1_.price_unit as price_unit0_ from servicegroup_content accessoria0_, servicelevel accessoria1_ where accessoria0_.servicegroup_id=? and accessoria0_.servicelevel_id=accessoria1_.servicelevel_id


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 20, 2004 3:34 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I always hated this kind of mapping, i think it throws away the natural polymorphism of the relational model, but it works in HB3. You can make it work in HB2 by specifying a where attribute in the collection mapping.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 20, 2004 3:52 pm 
Regular
Regular

Joined: Mon Sep 20, 2004 8:42 am
Posts: 58
Location: Boston, US
Since my class hierarchy was simple, I went with the table-per-hierarchy approach. Which mapping strategy would you recommend instead?

The 'where' attribute allows criteria on the link table (servicegroup_content) in this case, however the discriminator of interest in the 'type' column in the ServiceLevel table.

Thanks,
Sanjiv


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 20, 2004 4:24 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
oh, ok.

try table per subclass.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 19, 2005 2:25 pm 
Regular
Regular

Joined: Mon Sep 20, 2004 8:42 am
Posts: 58
Location: Boston, US
This still doesnt work in Hibernate 3.0.1. Even in the case of a 1-n mapping it fails.

Code:
   <class name="ServiceLevel" table="servicelevel">
      <id name="id" column="servicelevel_id" type="long" unsaved-value="null">
         <generator class="sequence">
            <param name="sequence">servicelevel_sequence</param>
         </generator>
      </id>
      <discriminator column="type"/>

      <property name="name" column="name"/>

      <subclass name="BaseServiceLevel" discriminator-value="0"/>
      <subclass name="Accessorial" discriminator-value="1"/>
   </class>

<class name="Engagement" table="engagement" lazy="false">
   <id name="id" column="engagement_id" type="long" unsaved-value="null">
      <generator class="sequence">
         <param name="sequence">engagement_sequence</param>
      </generator>
   </id>

   <property name="name" column="name"/>

   <set name="baseServiceLevels" inverse="true" lazy="true" table="servicelevel" cascade="all-delete-orphan">
      <key column="engagement_id"/>
      <one-to-many class="BaseServiceLevel"/>
   </set>
   <set name="accessorials" inverse="true" lazy="true" table="servicelevel" cascade="all-delete-orphan">
      <key column="engagement_id"/>
      <one-to-many class="Accessorial"/>
   </set>
</class>




Test code :
Code:
      Engagement e = engagementDao.getEngagement(new Long(-1000));
      Set baseServices = e.getBaseServiceLevels();
      Set accessorials = e.getAccessorials();
      for (Iterator iterator = baseServices.iterator(); iterator.hasNext();)
      {
         Object o = (Object) iterator.next();
         System.out.println(o);
      }
      for (Iterator iterator = accessorials.iterator(); iterator.hasNext();)
      {
         Object o = (Object) iterator.next();
         System.out.println(o);
      }


In Hibernate 2.1.8, one set used to get initialized with all entries and the other would be empty however in Hibernate 3, an exception is raised.

Code:
org.hibernate.WrongClassException: Object with id: -1011 was not of the specified subclass: Accessorial (loaded object was of wrong class)
   at org.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:824)
   at org.hibernate.loader.Loader.getRow(Loader.java:780)
   at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:295)
   at org.hibernate.loader.Loader.doQuery(Loader.java:389)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:208)
   at org.hibernate.loader.Loader.loadCollection(Loader.java:1367)
   at org.hibernate.loader.collection.OneToManyLoader.initialize(OneToManyLoader.java:107)
   at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:488)
   at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
   at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1356)
   at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:171)
   at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:48)
   at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:134)
   at EngagementDAOTestCase.testEngagement2(EngagementDAOTestCase.java:68)


SQL

Code:
select baseservic0_.engagement_id as engagement6___, baseservic0_.servicelevel_id as servicel1___, baseservic0_.servicelevel_id as servicel1_7_, baseservic0_.name as name16_7_,  baseservic0_.engagement_id as engagement6_16_7_,  engagement2_.engagement_id as engagement1_1_, engagement2_.name as name3_1_,  from servicelevel baseservic0_, engagement engagement2_, where baseservic0_.engagement_id=?

select accessoria0_.engagement_id as engagement6___, accessoria0_.servicelevel_id as servicel1___, accessoria0_.servicelevel_id as servicel1_7_, accessoria0_.name as name16_7_,  accessoria0_.engagement_id as engagement6_16_7_,  engagement2_.engagement_id as engagement1_1_, engagement2_.name as name3_1_,  from servicelevel accessoria0_, engagement engagement2_, where accessoria0_.engagement_id=?



As you can see the queries for baseservices and accessorials do not have a criteria with discriminator value.

For the 1-many case I can use the "where" criteria in the subclass mapping but as pointed out earlier, I cant use where for the many-many case.

Sanjiv


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jan 30, 2006 10:36 am 
Beginner
Beginner

Joined: Mon Nov 24, 2003 5:39 am
Posts: 26
Location: France
I've triied this as well with Hibernate 3.1 and I get the same error.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.