-->
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.  [ 3 posts ] 
Author Message
 Post subject: Mapping problem - one to many *and* one to one
PostPosted: Mon May 23, 2005 9:47 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
I've got a problem writing a mapping to a legacy database of mine. I gave two entities; company and currency. A company can have any number of currencies defined for it. So Company has a standard one to many relationship with it's currencies. Each company also has a single reporting currency - a one to one relationship.

My mappings look like this:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>

    <class name="foo.bar.Company" table="MACPFCO0">

        <id name="company" type="integer" column="COCMCD">
            <meta attribute="field-description">Company Code</meta>
            <meta attribute="use-in-tostring">true</meta>
            <generator class="assigned"/>
        </id>

        <property name="name" column="COCMNM" not-null="true" length="30" type="string">
            <meta attribute="field-description">Company Name</meta>
        </property>

        <map name="currencies" lazy="true" cascade="all-delete-orphan" sort="natural">
            <key>
                <column name="CCCMCC"/>
            </key>
            <index column="CCISCD" type="string"/>
            <one-to-many class="foo.bar.Currency"/>
        </map>

        <!-- This is wrong -->
        <many-to-one name="reportingCurrency" class="foo.bar.Currency" cascade="save-update" insert="false" update="false" unique="true">
            <column name="COCMCD"/>
            <column name="CORPCY"/>
        </many-to-one>

    </class>

</hibernate-mapping>

And:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>

    <class name="foo.bar.Currency" table="MACPFCC0">
        <meta attribute="class-description">
      Details of a currency.
      @author Simon Brunning
    </meta>

        <composite-id name="CurrencyKey" class="foo.bar.CurrencyKey">

            <key-many-to-one name="company" class="foo.bar.Company">
                <meta attribute="field-description">Company</meta>
                <meta attribute="use-in-tostring">true</meta>
                <column name="CCCMCC"/>
            </key-many-to-one>

            <key-property name="iso" type="string" length="3" column="CCISCD">
                <meta attribute="field-description">ISO Currency Code</meta>
                <meta attribute="use-in-tostring">true</meta>
            </key-property>

        </composite-id>

        <property name="name" column="CCCYNM" length="30" not-null="true" type="string">
            <meta attribute="field-description">Currency Name</meta>
        </property>

    </class>

</hibernate-mapping>

I can query my companies easily enough with this mapping, but if I query the companies, I get an exception:

Code:
Exception in thread "main" java.lang.StackOverflowError
   at java.lang.String.toCharArray(Unknown Source)
   at com.ibm.as400.access.JDSQLTokenizer.scanForTokens(JDSQLTokenizer.java:207)
   at com.ibm.as400.access.JDSQLTokenizer.<init>(JDSQLTokenizer.java:96)
   at com.ibm.as400.access.JDSQLTokenizer.<init>(JDSQLTokenizer.java:81)
   at com.ibm.as400.access.JDEscapeClause.parse(JDEscapeClause.java:146)
   at com.ibm.as400.access.JDSQLStatement.<init>(JDSQLStatement.java:371)
   at com.ibm.as400.access.AS400JDBCConnection.prepareStatement(AS400JDBCConnection.java:1850)
   at com.ibm.as400.access.AS400JDBCConnection.prepareStatement(AS400JDBCConnection.java:1677)
   at net.sf.hibernate.impl.BatcherImpl.getPreparedStatement(BatcherImpl.java:263)
   at net.sf.hibernate.impl.BatcherImpl.getPreparedStatement(BatcherImpl.java:236)
   at net.sf.hibernate.impl.BatcherImpl.prepareQueryStatement(BatcherImpl.java:67)
   at net.sf.hibernate.loader.Loader.prepareQueryStatement(Loader.java:784)
   at net.sf.hibernate.loader.Loader.doQuery(Loader.java:269)
   at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
   at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
   at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
   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:413)
   at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
   at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:2001)
   at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1963)
   at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
   at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:208)
   at net.sf.hibernate.type.ComponentType.resolveIdentifier(ComponentType.java:405)
   at net.sf.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:145)
   at net.sf.hibernate.loader.Loader.getKeyFromResultSet(Loader.java:431)
   at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:205)
   at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
   at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
   at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:941)
   at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:961)
   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:413)
   at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2131)
   at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:2001)
   at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1963)
   at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
   at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:208)
   at net.sf.hibernate.type.ComponentType.resolveIdentifier(ComponentType.java:405)
   at net.sf.hibernate.type.ComponentType.nullSafeGet(ComponentType.java:145)
   at net.sf.hibernate.loader.Loader.getKeyFromResultSet(Loader.java:431)
   at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:205)
...

And so on, and on, and on... (You'll notice there's a loop in there.)

For test purposes, I let Hibernate generate a schema for this mapping. (I've occasionally found this useful in the past - it allows you to see what Hibernate is expecting the database to look like. If the legacy database to which you are mapping looks significantly different to what Hibernate comes up with, then you have a problem.) The generated database that Hibernate comes up with in this case is utterly useless; there are constraints in both directions. You can't insert a company, 'cos there is no currency to use as its reporting currency, and you can't insert a currency without a company. The existing legacy schema doesn't have the constraints defined - the constraint is enforced in code - so it all works fine there.

I can see that this relationship is problematical in relational terms, but it makes perfect sense in business terms. Is it possible to write a Hibernate mapping to represent this relationship?

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject: Correction
PostPosted: Mon May 23, 2005 10:39 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
Quote:
if I query the companies, I get an exception

If I query the currencies, I should have said.

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


Top
 Profile  
 
 Post subject: Workarounds?
PostPosted: Tue May 24, 2005 5:06 am 
Beginner
Beginner

Joined: Tue May 10, 2005 6:25 am
Posts: 20
Location: London
I can think of two workarounds. I could make the reporting currency code available as a property rather than relating back to the current table directly. Retrieving the currency object would then be the client code's job.

Or, perhaps I could try building the company to currency link as a one to many. I'm not even sure that that would work.

Besides, I really want to fix this problem properly, for one and for all. I'll probably come across a lot of this kind of relationship as I map more of my legacy database.

_________________
Cheers,
Simon B,
simon@brunningonline.net,
http://www.brunningonline.net/simon/blog/


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