-->
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.  [ 1 post ] 
Author Message
 Post subject: One-to-one relationship with polymorphic entity
PostPosted: Sat Nov 07, 2009 10:58 pm 
Newbie

Joined: Wed Jun 17, 2009 11:08 am
Posts: 7
Hello there:

the application I'm working on requires two entities with a one-to-one relationship, with one end of the relationship being polymorphic. For the sake of illustration, I'll use a variation of an example from the "Java Persistence with Hibernate" book. Consider the entities from section "7.3.1 Polymorphic many-to-one associations":

Code:
+-----------+    default    +------------------+
|   User    | ------------> |  BillingDetails  |
+-----------+               |   < abstract >   |
                            +------------------+
                                     ^
                                     |
                          +-----------------------+
                          |                       |
                          |                       |
                 +-----------------+       +-------------------+       
                 |  CreditCard     |       |    BankAccount    |
                 +_________________+       +___________________+

Here, "default" is a one-to-one relationship that may vary over time: a User may start with a CreditCard instance as its default BillingDetails, but later this can be changed so that a BankAccount instance becomes the default. At any one time, only one concrete BillingDetails subclass should be associated with the User.

My database schema is using a single table per-class-hierarchy strategy along the lines of:

Code:
+-------------------------+             +--------------------------+     
|          USER           |             |      BILLING_DETAILS     |
|-------------------------|             |--------------------------|
| FK : billing_details_id | ----------> | PK : billing_details_id  |
|-------------------------|             |--------------------------|
| PK : user_id            |             | billing_type             |       
+-------------------------+             +--------------------------+

where "billing_type" is the discriminator column identifying whether the record corresponds to a CreditCard or BankAccount instance.

In summary, at any one time, there should be exactly one record in BILLING_DETAILS table for each record in USER.

I'm using the following xml Hibernate mapping files:

User.hbm.xml:
=========
Code:
<hibernate-mapping package="com.foo.domain">
   <class name="User" table="USER">

      <id name="id" column="user_id">
         <generator class="native" />
      </id>

      <!-- user properties go here -->
      
      <many-to-one name="billingDetails" class="BillingDetails"
                      column="billing_details_id" cascade="save-update"
                      unique="true" lazy="false" />
   </class>
</hibernate-mapping>

BillingDetails.hbm.xml:
==============
Code:
<hibernate-mapping package="com.foo.domain">
   <class name="BillingDetails" table="BILLING_DETAILS">

      <id name="id" column="billing_details_id">
         <generator class="native" />
      </id>
      
      <discriminator column="billing_type" />

      <!-- common billing details properties go here -->

      <subclass name="CreditCard" discriminator-value="CC">

         <!-- credit card specific properties go here -->

      </subclass>

      <subclass name="BankAccount" discriminator-value="BA">

         <!-- bank account  specific properties go here -->

      </subclass>
   </class>
</hibernate-mapping>

Creation works as expected, but I'm having problems with updates. Consider the following scenario: a User instance with a BankAccount exists in the database and the application receives an update request to replace the User's BankAccount with a CreditCard instance:
Code:
// Session is created and new transaction is opened

// Get the User from the db: user has BankAccount instance attached
User user = getSession().get( User.class, 55 );

// creditCard is a detached instance of type CreditCard passed in as a parameter:
// merge it with the the loaded billing details attached to the user
BillingDetails newDetails = (BillingDetails)getSession().merge( creditCard );

// Update user with new billing details (credit card)
user.setBillingDetails( newDetails );

// Persist changes to user
getSession().saveOrUpdate( user );

// Transaction is committed and session closed

For simplicity' sake, I extracted the steps above from various classes (SessionFilter, UserService, UserDao), just to illustrate the flow.

Before the update, the data looks like:

user:
----
user_id = 55
billing_details_id = 56

billing_details:
---------------
billing_details_id = 56
billing_type = BA

After the update, I get:

user:
----
user_id = 55
billing_details_id = 57

billing_details:
---------------
billing_details_id = 56
billing_type = BA

billing_details_id = 57
billing_type = CC

Notice that the old billing_details record (id=56) still exists in the db and a new billing_details record (id=57) was created and associated with the user.

Ideally, what I want is to update the existing billing_details record with the new information, so that the db ends up like:

user:
----
user_id = 55
billing_details_id = 56

billing_details:
---------------
billing_details_id = 56
billing_type = CC

I am clearly doing something wrong, so I'd be happy to hear any suggestions/recommendations that anyone can give.

Let me know if I've left out any relevant information that may help clarify things.

Thank you in advance for any help.

Regards


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

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.