-->
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.  [ 4 posts ] 
Author Message
 Post subject: discriminator missing from where clause
PostPosted: Mon Jan 24, 2005 1:09 pm 
Newbie

Joined: Mon Dec 13, 2004 5:34 pm
Posts: 2
Location: Glasgow, Scotland
I am attempting to use the table-per-class hierarchy strategy to map different subclasses to a parent object by one-to-one associations.

It is possible to create a parent with these associations but when I attempt to retrieve the parent object I get:
net.sf.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: com.paulkearney.ch3.CreditCard (loaded object was of wrong class) on the attempted retrieval of the child (subclass) objects.

The where clause generated is missing the discriminator clause on the select of the associated child objects and the result is a cartesian product of the associated children.

When I run the generated SQL I get a cartesian product which is the root cause of the WrongClassException i.e. CreditCards being returned with BankAccounts and vice-versa. This explains what is happening but does give me much help in solving my problem.

Is what I am attempting to do possible? From reading the Hibernate documentation/book I think it should be.

If this is possible does anyone have an example?



Hibernate version: 2.1.7c

Mapping documents:
PARENT OBJECT DEFINITIONS
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class
name="com.paulkearney.ch3.Customer"
table="CUSTOMERS">

<id
name="id"
column="CUSTOMER_ID"
type="integer">
<generator class="increment"/>
</id>
<property
name="name"
column="NAME"
type="string"/>

<one-to-one name="creditCard"
class="com.paulkearney.ch3.CreditCard"
property-ref="customer"
cascade="all"
constrained="true"/>

<one-to-one name="bankAccount"
class="com.paulkearney.ch3.BankAccount"
property-ref="customer"
cascade="all"
constrained="true"/>
</class>
</hibernate-mapping>

CHILD OBJECT DEFINITIONS
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class
name="com.paulkearney.ch3.BillingDetails"
table="BILLING_DETAILS">

<meta attribute="scope-class">public abstract</meta>

<id
name="id"
column="BILLING_DETAILS_ID"
type="integer">
<generator class="increment"/>
</id>
<discriminator
column="BILLING_DETAILS_TYPE"
type="string"
force="true"/>

<property
name="name"
column="OWNER"
type="string"/>

<subclass
name="com.paulkearney.ch3.CreditCard"
discriminator-value="CC">
<meta attribute="scope-class">public</meta>
<property
name="customer"
column="CUSTOMER_ID"
type="integer"
not-null="true"/>
<property
name="type"
type="string"
column="CREDIT_CARD_TYPE"/>
</subclass>

<subclass
name="com.paulkearney.ch3.BankAccount"
discriminator-value="BA">
<meta attribute="scope-class">public</meta>
<property
name="customer"
column="CUSTOMER_ID"
type="integer"
not-null="true"/>
<property
name="bankName"
type="java.lang.String"
column="BANK_ACCOUNT_BANK_NAME"/>
</subclass>

</class>
</hibernate-mapping>

Code between sessionFactory.openSession() and session.close():
Customer customer = (Customer)session.load(Customer.class, id);

Full stack trace of any exception that occurs:
java.lang.RuntimeException: Failed
at com.paulkearney.ch3.CustomersTest.testAddCustomer(CustomersTest.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:186)
Caused by: net.sf.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: com.paulkearney.ch3.CreditCard (loaded object was of wrong class)
at net.sf.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:531)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:498)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:213)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:281)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:133)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:911)
at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:931)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59)
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51)
at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:415)
at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2130)
at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:2000)
at net.sf.hibernate.impl.SessionImpl.load(SessionImpl.java:1929)
at com.paulkearney.ch3.CustomerDAO.getCustomer(CustomerDAO.java:57)
at com.paulkearney.ch3.CustomersTest.testAddCustomer(CustomersTest.java:49)
... 15 more



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

The generated SQL (show_sql=true):
Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_2_, customer0_.NAME as NAME2_, creditcard1_.BILLING_DETAILS_ID as BILLING_1_0_, creditcard1_.CUSTOMER_ID as CUSTOMER4_0_, creditcard1_.CREDIT_CARD_TYPE as CREDIT_C5_0_, creditcard1_.OWNER as OWNER0_, bankaccoun2_.BILLING_DETAILS_ID as BILLING_1_1_, bankaccoun2_.CUSTOMER_ID as CUSTOMER4_1_, bankaccoun2_.BANK_ACCOUNT_BANK_NAME as BANK_ACC6_1_, bankaccoun2_.OWNER as OWNER1_ from CUSTOMERS customer0_ left outer join BILLING_DETAILS creditcard1_ on customer0_.CUSTOMER_ID=creditcard1_.CUSTOMER_ID left outer join BILLING_DETAILS bankaccoun2_ on customer0_.CUSTOMER_ID=bankaccoun2_.CUSTOMER_ID where customer0_.CUSTOMER_ID=?

DDLs
CREATE TABLE BILLING_DETAILS (
BILLING_DETAILS_ID NUMBER(4) NOT NULL,
BILLING_DETAILS_TYPE VARCHAR2(2) NOT NULL,
CUSTOMER_ID NUMBER(4) NOT NULL,
OWNER VARCHAR(20) NOT NULL,
CREDIT_CARD_TYPE VARCHAR2(20),
BANK_ACCOUNT_BANK_NAME VARCHAR2(20),
CONSTRAINT BILLING_DETAILS_PK
PRIMARY KEY(BILLING_DETAILS_ID),
CONSTRAINT CUSTOMERS_FK
FOREIGN KEY(CUSTOMER_ID) REFERENCES CUSTOMERS(CUSTOMER_ID));

CREATE TABLE CUSTOMERS (
CUSTOMER_ID NUMBER(4) NOT NULL,
NAME VARCHAR2(20) NOT NULL,
CONSTRAINT CUSTOMERS_PK
PRIMARY KEY(CUSTOMER_ID);

Debug level Hibernate log excerpt:


Top
 Profile  
 
 Post subject: discriminator missing from where clause
PostPosted: Wed Jan 26, 2005 10:06 am 
Newbie

Joined: Wed Jan 26, 2005 9:54 am
Posts: 1
Location: Luxembourg
Have you seen this thread?

http://forum.hibernate.org/viewtopic.ph ... s+onetoone

In the response from Gavin, the <set> tags specify the where clause separately for each subclass

hope this helps


Top
 Profile  
 
 Post subject: Same problem
PostPosted: Thu Jan 27, 2005 7:42 am 
Newbie

Joined: Thu Jan 27, 2005 7:25 am
Posts: 1
I'm having the same problem and can solve it using a set. However a set doesn't correctly model my data, I need a one-to-one relationship but when I use one-to-one the join clause in the generated sql doesn't include the discriminator value.

Surely, hibernate should be able to join using the discriminator-value of the subclass referenced in the one-to-one element.

Is this a hibernate bug???


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 18, 2007 8:11 am 
Newbie

Joined: Wed Apr 18, 2007 7:22 am
Posts: 4
The problem with using a custom Where clause is that you have to update it every time you add more subclasses of the class you intend to retrieve. For example, if you make CreditCard abstract and you add Visa, MasterCard and Amex as subclasses of CreditCard, then you would need to update the where clause to something like the following:

where = "BILLING_DETAILS_TYPE IN ( 'V' , 'MC' , 'AX' )"

A better approach is to use force="true" in the discriminator element: <discriminator column="..." force="true" />. This causes Hibernate to include a condition on the discriminator column in the Where clause of the generated SQL. The condition will include all subclasses, so you don't have to manually maintain any Where clauses.

This feature is also available through the Hibernate annotation @org.hibernate.annotations.ForceDiscriminator but it is not a JPA standard.


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