views:

359

answers:

2

Hi,

The problem looks like this:

  1. A Product table. 3 joined-subclasses: DVD, CD, Book.

  2. A Role table (composite id: NAME, ROLE, PRODUCT), and subclasses by discriminator column ROLE: actor, director, artist, author, etc.. which are mapped to Actor, Director, Artist, Author java classes; (pretty usual I guess) ...

  3. A Book has authors, a CD artists, a DVD actors and directors - these are all modelled via set with a one-to-many relation pointing to the class of the items, e.g. Author, Director, Artist, etc.. which are just subclasses of Role (see 2.)

As long as a joined-subclass has only one such set (of people/roles), all works fine. But when it has two, like DVD, actors and directors, Hibernate throws a WrongClassException?

XML excerpt (Product.hbm.xml):

<joined-subclass name="media.DVD" table="V_DVD"  lazy="false">

    <key column="IDPRODUCT"/>
    <property column="FORMAT" name="format" type="string"/>

    ...
    <set name="actors" lazy="false">
       <key column="IDPRODUCT"/>
       <one-to-many class="media.DVD$Actor"/>
    </set>

    <set name="directors" lazy="false">
       <key column="IDPRODUCT"/>
       <one-to-many class="media.DVD$Director"/>
    </set>
    ...
</joined-subclass>

XML (Person.hbm.xml):

<class name="media.Person" table="V_ROLE">
    <composite-id>
        <key-property column="NAME" name="name" type="string"/>
        <key-property column="ROLE" name="role" type="string"/>
        <key-many-to-one class="media.Product" column="IDPRODUCT" 
          name="product"/>
    </composite-id>

    <discriminator column="ROLE" insert="false" type="string"/>

    <property name="name"/>
    <property name="role"/>

    <many-to-one class="media.Product" column="IDPRODUCT" 
      insert="false" name="product" update="false"/>

    <subclass discriminator-value="author" name="media.Book$Author"/>
    <subclass discriminator-value="artist" name="media.Music$Artist"/>
    <subclass discriminator-value="creator" name="media.DVD$Creator"/>
    <subclass discriminator-value="director" name="media.DVD$Director"/>
    <subclass discriminator-value="actor" name="media.DVD$Actor"/>

</class>

It seems somewhat ok to me, yet it throws an exception. Thank you for any idea!

A: 

I've got to say, this is a rather esoteric mapping. Why are you using a composite key (with discriminator being a part of it no less) instead of surrogate?

One possible issue here is you may be manually setting discriminator value (via role property) to something other than what it should be for given subclass. Hibernate won't be able to overwrite it (discriminator is mapped with insert="false") and this would cause a WrongClassException on subsequent select.

It's also possible that there' something funky going on in the Product mapping from which media.DVD extends and which you didn't include. Can you add that as well as provide full stack trace?

ChssPly76
A: 

Hi,

The problem is basically that your model is not normalized: You tell hibernate that there is a composite key, but you use only part of that key to reference the table.

I think you can implement this by either having a set of people in your product and each person has a role, or by mapping each set to a separate (linking) table with your person table.

Another more esoteric approach would be to map to a MultiMap: In fact you have a Map<Role, Set<Person>> in your product. Hibernate does not support this out of the box, but I once wrote a UserType for this.

Cheers,

-Maarten

Maarten Winkels
Not sure where you got this from. OP's is using composite key for child (Person), parent (media.DVD) has a single (IDPRODUCT) key.
ChssPly76