-->
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: Problem mapping composite-id and 1:n with unique foreign key
PostPosted: Wed Feb 11, 2009 11:37 am 
Newbie

Joined: Wed Feb 11, 2009 11:27 am
Posts: 1
Hi,

we are using composite-ids for the entities. I know this isn't recommned but it's mandatory for our application.

We want to map relations only with a part of the composite-id.
The mapping for 1:1-relations works fine, but 1:n doesn't work.

Here's the mapping:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="de.jbfagree.history.test.onetomany">
   <class name="Person" table="person">
      <!-- composite-id -->
      <composite-id>
         <key-property name="oid" column="oid" />
         <key-property name="knownOn" column="known_on" type="long" />
      </composite-id>

      <!-- mapped oid from composite-id -->
      <property name="oid" column="oid" update="false" insert="false" />

      <!-- field -->
      <property name="unknownOn" column="unknown_on" type="long" />

      <!-- field -->
      <property name="name" type="text" />

      <!-- one-to-many to Account -->
      <bag name="accounts" cascade="all">
         <!-- only use oid-field as foreign-key reference -->
         <!-- unique foreign key from person.oid on account.person_id -->
         <key column="person_id" property-ref="oid" not-null="true" update="false"/>
         <one-to-many class="Account" />
      </bag>
   </class>

   <class name="Account" table="account">
      <!-- composite-id -->
      <composite-id>
         <key-property name="oid" column="oid" />
         <key-property name="knownOn" column="known_on" type="long" />
      </composite-id>

      <!-- mapped oid from composite-id -->
      <property name="oid" column="oid" update="false" insert="false" />
   
      <!-- field -->
      <property name="unknownOn" column="unknown_on" type="long" />

      <!-- field -->
      <property name="accountNr" type="int" />
   </class>
</hibernate-mapping>


The exception depends on how the one-to-many is mapped.

If the one-to-many key is mapped with "update=false not-null=true" the following error occurs during save:

Code:
java.lang.ClassCastException: de.jbfagree.history.test.onetomany.Person
   at org.hibernate.type.StringType.toString(StringType.java:67)
   at org.hibernate.type.NullableType.nullSafeToString(NullableType.java:117)
   at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:158)
   at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:131)
   at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2025)
   at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2271)
   at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2688)
   at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
   at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
   at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
   at de.jbfagree.history.test.AbstractJPLTest.save(AbstractJPLTest.java:70)
   at de.jbfagree.history.test.onetomany.TestTemporalOneToMany.testCreateSingleRevision(TestTemporalOneToMany.java:68)
   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:164)
   at junit.framework.TestCase.runBare(TestCase.java:130)
   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:120)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)


The insert executed from hibernate:
Code:
    insert
    into
        account
        (unknown_on, accountNr, person_id, oid, known_on)
    values
        (?, ?, ?, ?, ?)



If the one-to-many key is mapped with "update=true not-null=false" the objetcs get correctly persisted but an error occurs during load:

Code:
16:05:17,323 ERROR BasicPropertyAccessor:191 - IllegalArgumentException in class: de.jbfagree.history.key.TemporalModel, getter method of property: oid
16:05:17,323  INFO SessionFactoryImpl:805 - closing
16:05:17,323  INFO DriverManagerConnectionProvider:170 - cleaning up connection pool: jdbc:mysql://localhost/bps
org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of de.jbfagree.history.key.TemporalModel.oid
   at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:195)
   at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:87)
   at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:93)
   at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:109)
   at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:376)
   at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:207)
   at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
   at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
   at org.hibernate.engine.StatefulPersistenceContext.getCollectionOwner(StatefulPersistenceContext.java:701)
   at org.hibernate.engine.loading.CollectionLoadContext.getLoadingCollection(CollectionLoadContext.java:130)
   at org.hibernate.loader.Loader.readCollectionElement(Loader.java:1026)
   at org.hibernate.loader.Loader.readCollectionElements(Loader.java:669)
   at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:614)
   at org.hibernate.loader.Loader.doQuery(Loader.java:724)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
   at org.hibernate.loader.Loader.doList(Loader.java:2228)
   at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
   at org.hibernate.loader.Loader.list(Loader.java:2120)
   at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401)
   at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:361)
   at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
   at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1148)
   at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
   at org.hibernate.impl.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:835)
   at de.jbfagree.history.test.onetomany.TestTemporalOneToMany.getPerson(TestTemporalOneToMany.java:105)
   at de.jbfagree.history.test.onetomany.TestTemporalOneToMany.testCreateSingleRevision(TestTemporalOneToMany.java:86)
   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:164)
   at junit.framework.TestCase.runBare(TestCase.java:130)
   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:120)
   at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
   at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
   at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.lang.IllegalArgumentException: java.lang.ClassCastException@16c9867
   at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
   at java.lang.reflect.Method.invoke(Unknown Source)
   at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:169)
   ... 41 more


The select executed from hibernate:

Code:
select
        person0_.oid as oid0_0_,
        person0_.known_on as known2_0_0_,
        accounts1_.oid as oid1_1_,
        accounts1_.known_on as known2_1_1_,
        person0_.unknown_on as unknown3_0_0_,
        person0_.name as name0_0_,
        accounts1_.unknown_on as unknown3_1_1_,
        accounts1_.accountNr as accountNr1_1_,
        accounts1_.person_id as person5_0__,
        accounts1_.oid as oid0__,
        accounts1_.known_on as known2_0__
    from
        person person0_
    inner join
        account accounts1_
            on person0_.oid=accounts1_.person_id
    where
        person0_.oid=?


Here are the classes:

TemporalModel.java (Superclass)
Code:
package de.jbfagree.history.key;

import java.io.Serializable;

public abstract class TemporalModel implements Serializable {
   private String oid;
   private Long knownOn;
   private Long unknownOn;

   public String getOid() {
      return oid;
   }

   public void setOid(String oid) {
      this.oid = oid;
   }

   public Long getKnownOn() {
      return knownOn;
   }

   public void setKnownOn(Long knownOn) {
      this.knownOn = knownOn;
   }

   public Long getUnknownOn() {
      return unknownOn;
   }

   public void setUnknownOn(Long unknownOn) {
      this.unknownOn = unknownOn;
   }

   @Override
   public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((knownOn == null) ? 0 : knownOn.hashCode());
      result = prime * result + ((oid == null) ? 0 : oid.hashCode());
      return result;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      TemporalModel other = (TemporalModel) obj;
      if (knownOn == null) {
         if (other.knownOn != null)
            return false;
      } else if (!knownOn.equals(other.knownOn))
         return false;
      if (oid == null) {
         if (other.oid != null)
            return false;
      } else if (!oid.equals(other.oid))
         return false;
      return true;
   }
}


Person.java
Code:
package de.jbfagree.history.test.onetomany;

import java.util.ArrayList;
import java.util.List;

import de.jbfagree.history.Versioned;
import de.jbfagree.history.VersioningType;
import de.jbfagree.history.key.TemporalModel;

public class Person extends TemporalModel {
   private String name;
   private List<Account> accounts;

   public Person() {
      accounts = new ArrayList<Account>();
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public List<Account> getAccounts() {
      return accounts;
   }

   public void setAccounts(List<Account> accounts) {
      this.accounts = accounts;
   }
}


Account.java
Code:
package de.jbfagree.history.test.onetomany;

import de.jbfagree.history.Versioned;
import de.jbfagree.history.VersioningType;
import de.jbfagree.history.key.TemporalModel;

public class Account extends TemporalModel {
   private int accountNr;

   public int getAccountNr() {
      return accountNr;
   }

   public void setAccountNr(int accountNr) {
      this.accountNr = accountNr;
   }
}


The hibernate-configuration

Code:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   <session-factory name="foo">
      <property name="hibernate.connection.password">pass</property>
      <property name="hibernate.connection.username">user</property>
      <property name="hibernate.connection.url">jdbc:mysql://<url> </property>
      <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

      <property name="hibernate.show_sql">true</property>
      <property name="hibernate.format_sql">true</property>
      <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

      <property name="hibernate.hbm2ddl.auto">create</property>

      <mapping resource="model.hbm.xml" />
   </session-factory>
</hibernate-configuration>


I know why the error occurs but I don't know how to fix it. According to documentation this should work fine.
We can't change the type of mapping. Also, it's not possible to use a bidirectional one-to-many.

Is this a bug or a "not really supported feature"?

Thanks for help, kind regards

sk


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.