-->
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.  [ 12 posts ] 
Author Message
 Post subject: Must have same number of columns as the referenced pk
PostPosted: Thu Jan 27, 2005 10:18 am 
Newbie

Joined: Mon Sep 27, 2004 3:01 am
Posts: 17
I'm getting the following exception from Hibernate:
net.sf.hibernate.MappingException: Foreign key (CANDIDATE [APPOINTEDROLE])) must have same number of columns as the referenced primary key (CMLOOKUPS [TABLENAME,LOOKUP])

And apparently this is due to us having an association where CANDIDATE.APPOINTEDROLE is a foreign key column to a table named CMLOOKUPS which has a two-column composite primary key, the other column (CMLOOKUPS.TABLENAME) acting also as a discriminator column (the CMLOOKUPS table hosts a class hierarchy).

--------------------------------------------------------------------------------

Hibernate version:
2.1.7c

Mapping documents:
Code:
<hibernate-mapping package="com.company.domain">

   <class name="Lookup" table="CMLOOKUPS" schema="REQUIREMENTCT">
      <composite-id name="lookupId" class="com.company.domain.id.LookupId">
         <key-property name="type" column="TABLENAME" type="string"/>
         <key-property name="id" column="LOOKUP" type="string"/>
      </composite-id>

      <discriminator column="TABLENAME" type="string" insert="false" />

      <subclass name="AppointedRole" discriminator-value="AppointedRole" />
      <subclass name="..." discriminator-value="..." />
      <subclass name="..." discriminator-value="..." />
      <subclass name="..." discriminator-value="..." />
   </class>

   <class name="Candidate" table="CANDIDATE" schema="REQUIREMENTCT">
      <!-- omitted some properties -->

      <component name="healthAndSafetyInfo" class="HealthAndSafetyInfo">
         <parent name="candidate"/>
         <!-- omitted some properties -->

         <!-- adding this to the mapping file causes the exception be thrown -->
         <many-to-one name="appointedRole" class="AppointedRole" column="APPOINTEDROLE"/>
      </component>
   </class>

</hibernate-mapping>



Code between sessionFactory.openSession() and session.close():
Code:
/**
* Here's the setup method from which the exception is propagated to screen...
*/
public abstract class HibernateTestCase extends junit.framework.TestCase {
    protected Session session = null;
    protected Transaction tx = null;

    protected void setUp() throws Exception
    {
        SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();
   session = sessionFactory.getSession();
        tx = session.beginTransaction();
    }
}

/**
* And this is the class that creates and configures the SessionFactory.
*/
public class HibernateSessionFactory {
    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                cfg.configure(CONFIG_FILE_LOCATION);
                sessionFactory = cfg.buildSessionFactory();
            } catch (Exception e) {
                // THIS IS WHERE I GOT THE STACK TRACE FROM
                e.printStackTrace();
            }
        }
        return sessionFactory;
    }
}

/**
* The super class for all objects persisted into the CMLOOKUPS table.
*/
public class Lookup {

    public void setLookupId(LookupId id) { this.lookupId = id; }

    public LookupId getLookupId() { return this.lookupId; }
   
    // omitted other getters/setters
}

/**
* The primary key class for the CMLOOKUPS table, i.e. to all children of the Lookup class.
*/
public class LookupId {

    public String getId() { return this.id; }

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

    public String getType() { return this.type; }

    public void setType(String type) { this.type = type; }

}

/**
* The subclass of Lookup that causes problems.
*/
public class AppointedRole extends Lookup {
    // empty
}

/**
* Another class that has an association to the AppointedRole class.
*/
public class Candidate {

    public AppointedRole getAppointedRole() { return this.appointedRole; }

    public void setAppointedRole(AppointedRole role) { this.appointedRole = role; }

    // omitted other getters/setters
}




Full stack trace of any exception that occurs:
Code:
net.sf.hibernate.MappingException: Foreign key (CANDIDATE [APPOINTEDROLE])) must have same number of columns
  as the referenced primary key (CMLOOKUPS [TABLENAME,LOOKUP])
   at net.sf.hibernate.mapping.ForeignKey.setReferencedTable(ForeignKey.java:67)
   at net.sf.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:696)
   at net.sf.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:671)
   at net.sf.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:789)
   at com.company.storage.HibernateSessionFactory.getSessionFactory(HibernateSessionFactory.java:64)
   at com.company.storage.HibernateTestCase.setUp(HibernateTestCase.java:36)
   at com.company.storage.LookupMappingTest.setUp(LookupMappingTest.java:37)
   at junit.framework.TestCase.runBare(TestCase.java:125)
   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)



Name and version of the database you are using:
Oracle 9.0.2.x, although test code never reaches the database nor goes through a vendor-specific dialect class etc.

The generated SQL (show_sql=true):
None generated, exception thrown during configuration/creating the SessionFactory

Debug level Hibernate log excerpt:
Not available


Top
 Profile  
 
 Post subject: Many-to-one relationships with composite id.
PostPosted: Fri Jan 28, 2005 9:05 am 
Newbie

Joined: Fri Jan 28, 2005 8:58 am
Posts: 9
Hi,

Hibernate is very strict with composite ids. In order to map them, you have to specify the same values in the referring class.

So, your candidate class should be something like
Code:

<class name="Candidate" table="CANDIDATE" schema="REQUIREMENTCT">
      <!-- omitted some properties -->

      <component name="healthAndSafetyInfo" class="HealthAndSafetyInfo">
         <parent name="candidate"/>
         <!-- omitted some properties -->

         <!-- adding this to the mapping file causes the exception be thrown -->
         <many-to-one name="appointedRole" class="AppointedRole" column="APPOINTEDROLE">
[b]                <key name="type" column="TYPE_COLUMN_IN_THIS_TABLE"/>
                <key name="id" column="ID_COLUMN_IN_THIS_TABLE" />
          </many-to-one>
[/b]      </component>
   </class>


Hope this helps.


Top
 Profile  
 
 Post subject: Ought to be possible to associate to composite-id subclass
PostPosted: Fri Jan 28, 2005 10:23 am 
Newbie

Joined: Mon Sep 27, 2004 2:15 am
Posts: 11
Location: Helsinki, Finland
(I'm on the same project as Lasse)

Our problem is that we have a legacy database which we cannot easily change.

Code:
         <!-- adding this to the mapping file causes the exception be thrown -->
         <many-to-one name="appointedRole" class="AppointedRole" column="APPOINTEDROLE">
                <key name="type" column="TYPE_COLUMN_IN_THIS_TABLE"/>
                <key name="id" column="ID_COLUMN_IN_THIS_TABLE" />
          </many-to-one>
      </component>

Additionally, it should not be necessary to specify the "type" column, because we are referring to an instance of a subclass and it is sufficient to merely reference the subclass-specific id from the "candidate" table. Indeed, we realize that Hibernate does of course actually ultimately require values for both of the columns in the 2-column composite id of the subclass table, but the other value can be directly found as the "discriminator" value of the AppointedRole class, as specified in the mapping file of the "cmlookups" table.

Code:
<subclass name="AppointedRole" discriminator-value="AppointedRole" />


We are providing all the information that Hibenate needs to implement this association, but it would appear that this is not actually supported by Hibernate?

Is this a defect or an oversight, or are we missing something?


Top
 Profile  
 
 Post subject: Summary of our issue without example
PostPosted: Fri Jan 28, 2005 10:28 am 
Newbie

Joined: Mon Sep 27, 2004 2:15 am
Posts: 11
Location: Helsinki, Finland
Here I try to summarize our question in general terms.

Context. We have a table containing a class hierarchy. The table has a 2-column composite id, where the first column is the subclass discriminator, and the second column is the subclass instance id. We have another entity class, in its own table, that has a many-to-one association to a particular subclass.

Proposition. It ought to be possible to map the association from the entity class to the subclass by specifying (a) a many-to-one association to the named subclass in the entity class's mapping, and (2) having a single column in the entity class's table, which contains the subclass-specific id of the associated subclass instance. Together, (a) and (b) provide both the values for the 2-column composite id within the subclass table.

This would appear not to be supported in Hibernate. Or then I'm confused or missing something.


Top
 Profile  
 
 Post subject: composite keys
PostPosted: Fri Jan 28, 2005 1:02 pm 
Newbie

Joined: Fri Jan 28, 2005 8:58 am
Posts: 9
Although I did not have the 'discriminator' column as a part of a many-to-one relationship, I did have a multiple column many-to-one mapping requirement under similar circumstances.

In my case, while one of the columns was not a discrimnator column, it was a nullable key.

I could create a straight SQL query based on my problem but could not get Hibernate to do the same thing.

My colleague posted the issue to the forum and got a reply from Gavin that ours was a broken model and hence, Hibernate does not support such a thing.

While I understand that my model is kind-of broken (it's an old AS/400 legacy database which I have no control over - same as you), I did want to use Hibernate as it works for most other situations.

BOTTOM LINE: Some of the more complex composite-id mappings are not supported by Hibernate as it considers the underlying model to be 'broken'.

The only thing you can do is to work around the problem by creating a primary key class or an approach similar to what I described.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 28, 2005 4:28 pm 
Newbie

Joined: Mon Sep 27, 2004 2:15 am
Posts: 11
Location: Helsinki, Finland
Quote:
got a reply from Gavin that ours was a broken model and hence, Hibernate does not support such a thing.


I don't feel that our model is broken ... as I describe above, I feel that our model is entirely valid; if Gavin is of a different opinion, I'd really like to hear what he has to say.

Like I said, I'd like to know whether this is intentional in Hibernate or an oversight.

What we're gonna do is add the extra (stricly superfluous) column into our referring table, so that we can provide both of the columns for the composite id in our mapping. Ultimately, even if it's not strictly necessary, Hibernate will hide the details from the object model anyhow ...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 28, 2005 5:26 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
AFAICT, this kind of mapping is possible in HB3, and even in HB2, I have a feeling. You got to use a literal value in your association mapping. In HB2, this looks like: <column name="1"/>, or <column name="'foo'"/>. In HB3 it looks like <formula>1</formula> or <formula>'foo'</formula>.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jan 29, 2005 11:54 am 
Newbie

Joined: Mon Sep 27, 2004 2:15 am
Posts: 11
Location: Helsinki, Finland
Quote:
You got to use a literal value in your association mapping.


Oh, cool! That would be fabulous. I'm drooling :)

Will try this out right away Monday and report back to this topic asap.

Thanks.


Top
 Profile  
 
 Post subject: The literal column value works!
PostPosted: Mon Jan 31, 2005 7:07 am 
Newbie

Joined: Mon Sep 27, 2004 3:01 am
Posts: 17
Thanks, Gavin. The <column name="'fixed value'"/> works perfect.

I suppose someone should add a mention about this to the documentation?[/b]


Top
 Profile  
 
 Post subject: ClassCastException
PostPosted: Tue Dec 06, 2005 12:14 pm 
Beginner
Beginner

Joined: Wed Feb 23, 2005 10:37 am
Posts: 29
Hi guys,

I am trying out the formula (using HB3) to solve the same problem but am getting the ClassCastException:

Code:
java.lang.ClassCastException
   at org.hibernate.mapping.Set.createPrimaryKey(Set.java:55)
   at org.hibernate.mapping.Collection.createAllKeys(Collection.java:359)
   at org.hibernate.cfg.HbmBinder$SecondPass.doSecondPass(HbmBinder.java:2469)
   at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:884)
   at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:999)
   at dataaccess.HibernateTestCase.onSetUp(HibernateTestCase.java:30)
   at dataaccess.DataAccessTestCase.setUp(DataAccessTestCase.java:60)


Any tips would be appreciated.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 06, 2005 12:39 pm 
Beginner
Beginner

Joined: Wed Feb 23, 2005 10:37 am
Posts: 29
Sorry, forgot the mapping.
This is the the part that has a set mapping.

Code:
<set name="products" table="ppproduct">
            <key column="ppId"/>
            <many-to-many class="pp.PPProduct">
                <formula>'productId'</formula>
            </many-to-many>
        </set>


In the code from hibernate it looks like it casts Formula class to Column so there must be a mapping error or many-to-many association does not support this?

Code:
void createPrimaryKey() {
      if ( !isOneToMany() ) {
         PrimaryKey pk = new PrimaryKey();
         pk.addColumns( getKey().getColumnIterator() );
         Iterator iter = getElement().getColumnIterator();
         while ( iter.hasNext() ) {
            Column col = (Column) iter.next();
            .
                                    .
                                    .
                                    .
                                    .
                                    .


Top
 Profile  
 
 Post subject: Re: Must have same number of columns as the referenced pk
PostPosted: Thu Jun 03, 2010 2:46 pm 
Newbie

Joined: Mon Feb 09, 2009 11:52 am
Posts: 11
Can you show the end result of your mapping file? Having the same issue but doesn't seem to resolve mine...

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
   auto-import="true">
  <class name="AutomatedGrantSuggestions.DataAccess.Organization, AutomatedGrantSuggestions.DataAccess" lazy="false" table="ct_org_master">
    <id name="CtId" column="ct_id">
      <generator class="native" />
    </id>
    <property name="Name" column="ct_org_name1"/>
    <property name="Name2" column="ct_org_name2"/>
    <many-to-one name="Address" class="AutomatedGrantSuggestions.DataAccess.Address, AutomatedGrantSuggestions.DataAccess">
      <column name="Type" />
      <column name="CtId" />
    </many-to-one>
   
  </class>
  <class name="AutomatedGrantSuggestions.DataAccess.Address, AutomatedGrantSuggestions.DataAccess" lazy="false" table="ct_org_address">
    <composite-id>
      <key-many-to-one name="CtId" column="ct_id" />
      <key-many-to-one name="Type" column="ct_org_addr_type"/>
    </composite-id>
    <property name="Line1" column="ct_org_addr1"/>
    <property name="Line2" column="ct_org_addr2"/>
  </class>
</hibernate-mapping>


Gives me error...

Quote:
NHibernate.MappingException: An association from the table ct_org_address refers to an unmapped class: System.Int32.


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