-->
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: Confusing Behavior with Single Table Inheritance
PostPosted: Thu Dec 20, 2012 4:36 am 
Newbie

Joined: Thu Dec 20, 2012 3:38 am
Posts: 1
Hi,
The following is a scenario to illustrate a weird situation (at least for me) I have encountered.

Entity classes:
Code:
@Entity
@Table (name = "ACCOUNT")
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn (name = "ACCOUNT_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class Account {

   @Id
   @GeneratedValue
   @Column (name = "ACCOUNT_ID")
   private Long id;

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }
}

@Entity
@DiscriminatorValue (value = "SavingsAccount")
public class SavingsAccount extends Account {

   @OneToOne (mappedBy = "savingsAccount", fetch = FetchType.EAGER)
   private Customer customer;

   public Customer getCustomer() {
      return customer;
   }

   public void setCustomer(Customer customer) {
      this.customer = customer;
   }
}

@Entity
@DiscriminatorValue (value = "CheckingAccount")
public class CheckingAccount extends Account {

   @OneToOne (mappedBy = "checkingAccount", fetch = FetchType.EAGER)
   private Customer customer;

   public Customer getCustomer() {
      return customer;
   }

   public void setCustomer(Customer customer) {
      this.customer = customer;
   }
}

@Entity
@Table (name = "CUSTOMER")
public class Customer {

   @Id
   @GeneratedValue
   @Column (name = "CUSTOMER_ID")
   private Long id;

   @JoinColumn (name = "SAVINGS_ACCOUNT_ID", referencedColumnName = "ACCOUNT_ID")
   @OneToOne (optional = true, fetch = FetchType.LAZY)
   private SavingsAccount savingsAccount;

   @JoinColumn (name = "CHECKING_ACCOUNT_ID", referencedColumnName = "ACCOUNT_ID")
   @OneToOne (optional = true, fetch = FetchType.LAZY)
   private CheckingAccount checkingAccount;

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public SavingsAccount getSavingsAccount() {
      return savingsAccount;
   }

   public void setSavingsAccount(SavingsAccount savingsAccount) {
      this.savingsAccount = savingsAccount;
   }

   public CheckingAccount getCheckingAccount() {
      return checkingAccount;
   }

   public void setCheckingAccount(CheckingAccount checkingAccount) {
      this.checkingAccount = checkingAccount;
   }
}


SQL statements:
Code:
CREATE TABLE ACCOUNT (ACCOUNT_ID NUMBER NOT NULL, CONSTRAINT ACCOUNT_PK PRIMARY KEY (ACCOUNT_ID) ENABLE);
CREATE TABLE CUSTOMER (CUSTOMER_ID NUMBER NOT NULL, CHECKING_ACCOUNT_ID NUMBER, SAVINGS_ACCOUNT_ID NUMBER, CONSTRAINT CUSTOMER_PK PRIMARY KEY (CUSTOMER_ID) ENABLE);
ALTER TABLE CUSTOMER ADD CONSTRAINT FK_CHECKING_ACC FOREIGN KEY(CHECKING_ACCOUNT_ID) REFERENCES ACCOUNT (ACCOUNT_ID) ENABLE;
ALTER TABLE CUSTOMER ADD CONSTRAINT FK_SAVING_ACC FOREIGN KEY (SAVINGS_ACCOUNT_ID) REFERENCES ACCOUNT(ACCOUNT_ID) ENABLE;
ALTER TABLE ACCOUNT ADD (ACCOUNT_TYPE VARCHAR2(20));
INSERT INTO ACCOUNT (ACCOUNT_ID, ACCOUNT_TYPE) VALUES ('1', 'SavingsAccount');
INSERT INTO ACCOUNT (ACCOUNT_ID, ACCOUNT_TYPE) VALUES ('2', 'CheckingAccount');
INSERT INTO CUSTOMER (CUSTOMER_ID, CHECKING_ACCOUNT_ID, SAVING_ACCOUNT_ID) VALUES ('1', '2', '1');


When I run the following code to find the account with id 1, the customer field of the account is null.
Code:
Account savingsAccount = entityManager.find(Account.class, 1L);


The query created by hibernate is
Code:
SELECT account0_.ACCOUNT_ID      AS ACCOUNT2_18_2_,
  account0_.ACCOUNT_TYPE         AS ACCOUNT1_18_2_,
  customer1_.CUSTOMER_ID         AS CUSTOMER1_85_0_,
  customer1_.CHECKING_ACCOUNT_ID AS CHECKING2_85_0_,
  customer1_.SAVING_ACCOUNT_ID   AS SAVING3_85_0_,
  customer2_.CUSTOMER_ID         AS CUSTOMER1_85_1_,
  customer2_.CHECKING_ACCOUNT_ID AS CHECKING2_85_1_,
  customer2_.SAVING_ACCOUNT_ID   AS SAVING3_85_1_
FROM ACCOUNT account0_
LEFT OUTER JOIN CUSTOMER customer1_
ON account0_.ACCOUNT_ID=customer1_.SAVING_ACCOUNT_ID
LEFT OUTER JOIN CUSTOMER customer2_
ON account0_.ACCOUNT_ID   =customer2_.CHECKING_ACCOUNT_ID
WHERE account0_.ACCOUNT_ID=?


Although the account with id 1 is associated with the only customer in the database and hibernate performs a query to retrieve the relation; the account entity's customer field is not initialized properly. However, if I change the retrieval code to the following (note that I am retrieving a SavingsAccount now):

Code:
Account savingsAccount = entityManager.find(SavingsAccount.class, 1L);


The account's relation with the customer is initialized as expected with the following query generated:

Code:
SELECT savingsacc0_.ACCOUNT_ID   AS ACCOUNT2_18_1_,
  customer1_.CUSTOMER_ID         AS CUSTOMER1_85_0_,
  customer1_.CHECKING_ACCOUNT_ID AS CHECKING2_85_0_,
  customer1_.SAVING_ACCOUNT_ID   AS SAVING3_85_0_
FROM ACCOUNT savingsacc0_
LEFT OUTER JOIN CUSTOMER customer1_
ON savingsacc0_.ACCOUNT_ID   =customer1_.SAVING_ACCOUNT_ID
WHERE savingsacc0_.ACCOUNT_ID=?
AND savingsacc0_.ACCOUNT_TYPE='SavingsAccount'


My question is why hibernate is unable to construct the account object with the customer field initialized properly in the first case I mentioned? This has to be related with the fact that account subclasses CheckingAccount and SavingsAccount both have a one-to-one relation with the customer and hibernate is somehow unable to detect the correct customer associated with the account in case the retrieval is performed over the base class Account. Is this a bug or am I missing sth? I would be glad if someone explains hibernate's behavior. By the way hibernate version is 3.4.


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.