0

I have an interesting use-case where I'd like Hibernate to manage multiple one-to-many relationships to the same entity type.

For example: BookShelf fictionBooks relationship to Book(s), but also BookShelf nonFictionBooks mapped to Book(s). The Hibernate mapping would look something like this:

<class name="com.example.BookStore" table="BOOK_SHELF">
    <id name="id" type="long" column="bookShelfId">
        <generator class="native" />
    </id>
    <set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
        <key column="bookShelfId" />
        <one-to-many class="com.example.Book" />
    </set>
    <set name="nonFictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
        <key column="bookShelfId" />
        <one-to-many class="com.example.Book" />
    </set>
</class>
<class name="com.example.Book" table="SHELF_BOOK">
    <id name="id" type="long" column="shelfBookId">
        <generator class="native" />
    </id>
    <property name="name" not-null="true" unique="true"/>
</class>

Is there a way for the relationship owner BookShelf to specify some discriminator value which could be used to differentiate between Fiction and Non-Fiction books? If possible, the discriminator would be stored as an additional column in SHELF_BOOK table and Hibernate would automatically filter on that.

Is there a way to do this without resorting to either a many-to-many association or extending the Book entity with a Table per class strategy?

Prerak Tiwari
  • 3,436
  • 4
  • 34
  • 64
Saad Malik
  • 1,598
  • 1
  • 18
  • 20

2 Answers2

2

Ideally you should have a "type" or "flag" column in SHELF_BOOK table indicating the book is fiction or non-fiction.

Suppose you have added this "type" column, then I think you could specify a filter statement in the set:

<set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan"   lazy="false">
    <filter name="myfilter" condition=":type = 'FICTION'"/>
    <key column="bookShelfId" />
    <one-to-many class="com.example.Book" />
</set>

You can refer to http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters

  • That's actually a decent solution. Didn't know was an option in a relationship. Will accept this answer tomorrow if I don't get any better alternatives! – Saad Malik Aug 20 '15 at 01:16
  • Even more straightforward in your case would be to use [@org.hibernate.annotations.Where](http://stackoverflow.com/questions/7700071/how-to-use-where-in-jpa-hibernate), but the idea is the same. – OndroMih Aug 20 '15 at 13:21
1

From what you posted, I can say that in order to achieve what you wanted you need to modify your relationship owner BookShelf to only store reference to Book and add the property, say bookType, to Book entity.

<class name="com.example.BookStore" table="BOOK_SHELF">
    <id name="id" type="long" column="bookShelfId">
        <generator class="native" />
    </id>
    <set name="books" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
        <key column="bookShelfId" />
        <one-to-many class="com.example.Book" />
    </set>
</class>


<class name="com.example.Book" table="SHELF_BOOK">
    <id name="id" type="long" column="shelfBookId">
        <generator class="native" />
    </id>
    <property name="name" not-null="true" unique="true"/>
    <property name="bookType" not-null="true"/>
</class>

There is no other(except ManytoMany) way by which you can find out the type of book by looking into BookShelf entity. You can also use Single Table Strategy which will automatically add the discriminator to the inserted values but in order to do that you need to create two separate classes for FictionalBook and NonFictionalBook .

Prerak Tiwari
  • 3,436
  • 4
  • 34
  • 64
  • This silly _Book_ example is a gross oversimplification of the actual problem--the uses of FictionalBook vs NonFictionalBook are vastly different so it wouldn't make sense to combine them. – Saad Malik Aug 20 '15 at 01:44
  • Also I considered concrete classes of FictionalBook and NonFictionalBook so I could use discriminator, but it just seemed wrong to implement two completely empty classes. – Saad Malik Aug 20 '15 at 01:45