-->
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.  [ 5 posts ] 
Author Message
 Post subject: ClassCastException - merge() with one-to-one on FK
PostPosted: Fri Sep 30, 2005 11:23 am 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
Hibernate version: 3.1

All the mapping files, code, logs, etc. are below. I am getting a ClassCastException when calling merge() on an object (Station) that has a dependent object (StationState) with a one-to-one foreign key.

Here are my tables (generated by Hibernate Tools from mapping files, along with my POJOs):

Code:
create table nathan.station (station_id int8 not null unique, primary key (station_id));
create table nathan.stationstate (stationstate_id int8 not null unique, station_id int8 not null, primary key (stationstate_id));


Data in the tables looks like:

station table:
Code:
station_id
-----------
1


stationstate table:
Code:
stationstate_id  |  station_id
---------------  |  -----------
2                |  1


I load a Station object, clear the session, then call merge() to re-associate the Station with the session. You can see from the logs that the first time I load the object, it correctly loads the StationState along with the Station (using left outer join). On the merge, however, it loads first the Station, then tries to resolve associations. It loads the StationState ok, but it seems that it mistakenly thinks that station_id is the PK of stationstate (it prints out loader.Loader - loading entity: [com.nathan.hibernatetest.StationState#1] which I think is saying it thinks that station_id (1) is the PK of stationstate instead of stationstate_id (2)).

Then it tries to load StationState again, but using the Station object as the PK, causing a ClassCastException! Is my mapping file wrong, causing Hibernate to believe that the stationstate table is a PK/FK one-to-one instead of just a FK one-to-one?

How do I fix my Station mapping file so that Hibernate knows that StationState has its own PK?? I followed the docs in creating the association.

Thanks in advance for any help.

Mapping documents:

Code:
<class
      name="Station"
      table="station"
      schema="nathan">

      <id
         name="StationId"
         type="java.lang.Long">
         <column
            name="station_id"
            not-null="true"
            unique="true" />
         <generator class="native" />
      </id>

      <one-to-one
         name="StationState"
         class="StationState"
         property-ref="Station" />

   </class>


Code:
   <class
      name="StationState"
      table="stationstate"
      schema="nathan">

      <id
         name="StationStateId"
         type="java.lang.Long">
         <column
            name="stationstate_id"
            not-null="true"
            unique="true" />
         <generator class="native" />
      </id>

      <many-to-one
         name="Station"
         class="Station"
         unique="true">
         <column
            name="station_id"
            not-null="true" />
      </many-to-one>

   </class>

Code between sessionFactory.openSession() and session.close():

Code:
      Session s = sf.openSession();
      Transaction t = s.beginTransaction();
      
      Station station = (Station)s.get(Station.class, new Long(1));
      
      s.clear();
      
      try {
         s.merge(station);
      } catch (Exception e) {
         throw e;
      }
      
      t.commit();
      s.close();

Full stack trace of any exception that occurs:

Quote:
java.lang.ClassCastException
at org.hibernate.type.LongType.set(LongType.java:42)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:63)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:45)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1514)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1576)
at org.hibernate.loader.Loader.doQuery(Loader.java:661)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:223)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1782)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:47)
at org.hibernate.loader.entity.EntityLoader.loadByUniqueKey(EntityLoader.java:85)
at org.hibernate.persister.entity.AbstractEntityPersister.loadByUniqueKey(AbstractEntityPersister.java:1512)
at org.hibernate.type.EntityType.loadByUniqueKey(EntityType.java:365)
at org.hibernate.type.EntityType.resolve(EntityType.java:306)
at org.hibernate.type.EntityType.replace(EntityType.java:207)
at org.hibernate.type.TypeFactory.replace(TypeFactory.java:431)
at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:279)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:245)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:102)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:608)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:594)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:598)
at StationTest.testOne(StationTest.java:110)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
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:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)



Name and version of the database you are using:

PostgreSQL 8

The generated SQL (show_sql=true):

(See DEBUG Hibernate log:)

Debug level Hibernate log excerpt:

Quote:
3890 DEBUG [main] impl.SessionImpl - opened session at timestamp: 4620662712664064
3890 DEBUG [main] transaction.JDBCTransaction - begin
3890 DEBUG [main] jdbc.ConnectionManager - opening JDBC connection
3890 DEBUG [main] transaction.JDBCTransaction - current autocommit status: false
3890 DEBUG [main] jdbc.JDBCContext - before transaction completion
3906 DEBUG [main] def.DefaultLoadEventListener - loading entity: [com.nathan.hibernatetest.Station#1]
3906 DEBUG [main] def.DefaultLoadEventListener - attempting to resolve: [com.nathan.hibernatetest.Station#1]
3906 DEBUG [main] def.DefaultLoadEventListener - object not resolved in any cache: [com.nathan.hibernatetest.Station#1]
3906 DEBUG [main] entity.AbstractEntityPersister - Fetching entity: [com.nathan.hibernatetest.Station#1]
3906 DEBUG [main] loader.Loader - loading entity: [com.nathan.hibernatetest.Station#1]
3921 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
3921 DEBUG [main] hibernate.SQL - select station0_.station_id as station1_22_1_, stationsta1_.stationstate_id as stations1_23_0_, stationsta1_.station_id as station2_23_0_ from nathan.station station0_ left outer join nathan.stationstate stationsta1_ on station0_.station_id=stationsta1_.station_id where station0_.station_id=?
3921 DEBUG [main] jdbc.AbstractBatcher - preparing statement
3937 DEBUG [main] type.LongType - binding '1' to parameter: 1
3968 DEBUG [main] jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
3968 DEBUG [main] loader.Loader - processing result set
3968 DEBUG [main] loader.Loader - result set row: 0
3968 DEBUG [main] type.LongType - returning '2' as column: stations1_23_0_
3968 DEBUG [main] loader.Loader - result row: EntityKey[com.nathan.hibernatetest.StationState#2], EntityKey[com.nathan.hibernatetest.Station#1]
3968 DEBUG [main] loader.Loader - Initializing object from ResultSet: [com.nathan.hibernatetest.StationState#2]
3984 DEBUG [main] entity.AbstractEntityPersister - Hydrating entity: [com.nathan.hibernatetest.StationState#2]
3984 DEBUG [main] type.LongType - returning '1' as column: station2_23_0_
3999 DEBUG [main] loader.Loader - Initializing object from ResultSet: [com.nathan.hibernatetest.Station#1]
3999 DEBUG [main] entity.AbstractEntityPersister - Hydrating entity: [com.nathan.hibernatetest.Station#1]
3999 DEBUG [main] loader.Loader - done processing result set (1 rows)
3999 DEBUG [main] jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
3999 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
3999 DEBUG [main] jdbc.AbstractBatcher - closing statement
4015 DEBUG [main] loader.Loader - total objects hydrated: 2
4015 DEBUG [main] engine.TwoPhaseLoad - resolving associations for [com.nathan.hibernatetest.StationState#2]
4015 DEBUG [main] def.DefaultLoadEventListener - loading entity: [com.nathan.hibernatetest.Station#1]
4015 DEBUG [main] def.DefaultLoadEventListener - entity found in session cache
4015 DEBUG [main] engine.TwoPhaseLoad - done materializing entity [com.nathan.hibernatetest.StationState#2]
4015 DEBUG [main] engine.TwoPhaseLoad - resolving associations for [com.nathan.hibernatetest.Station#1]
4015 DEBUG [main] engine.TwoPhaseLoad - done materializing entity [com.nathan.hibernatetest.Station#1]
4015 DEBUG [main] engine.StatefulPersistenceContext - initializing non-lazy collections
4015 DEBUG [main] loader.Loader - done entity load
4031 DEBUG [main] engine.IdentifierValue - id unsaved-value: null
4031 DEBUG [main] def.AbstractSaveEventListener - detached instance of: com.nathan.hibernatetest.Station
4031 DEBUG [main] def.DefaultMergeEventListener - merging detached instance
4031 DEBUG [main] def.DefaultLoadEventListener - loading entity: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] def.DefaultLoadEventListener - attempting to resolve: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] def.DefaultLoadEventListener - object not resolved in any cache: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] entity.AbstractEntityPersister - Fetching entity: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] loader.Loader - loading entity: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
4031 DEBUG [main] hibernate.SQL - select station0_.station_id as station1_22_0_ from nathan.station station0_ where station0_.station_id=?
4031 DEBUG [main] jdbc.AbstractBatcher - preparing statement
4031 DEBUG [main] type.LongType - binding '1' to parameter: 1
4031 DEBUG [main] jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
4031 DEBUG [main] loader.Loader - processing result set
4031 DEBUG [main] loader.Loader - result set row: 0
4031 DEBUG [main] loader.Loader - result row: EntityKey[com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] loader.Loader - Initializing object from ResultSet: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] entity.AbstractEntityPersister - Hydrating entity: [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] loader.Loader - done processing result set (1 rows)
4031 DEBUG [main] jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
4031 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
4031 DEBUG [main] jdbc.AbstractBatcher - closing statement
4031 DEBUG [main] loader.Loader - total objects hydrated: 1
4031 DEBUG [main] engine.TwoPhaseLoad - resolving associations for [com.nathan.hibernatetest.Station#1]
4031 DEBUG [main] loader.Loader - loading entity: [com.nathan.hibernatetest.StationState#1]
4031 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
4031 DEBUG [main] hibernate.SQL - select stationsta0_.stationstate_id as stations1_23_0_, stationsta0_.station_id as station2_23_0_ from nathan.stationstate stationsta0_ where stationsta0_.station_id=?
4031 DEBUG [main] jdbc.AbstractBatcher - preparing statement
4031 DEBUG [main] type.LongType - binding '1' to parameter: 1
4031 DEBUG [main] jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
4031 DEBUG [main] loader.Loader - processing result set
4031 DEBUG [main] loader.Loader - result set row: 0
4046 DEBUG [main] type.LongType - returning '2' as column: stations1_23_0_
4046 DEBUG [main] loader.Loader - result row: EntityKey[com.nathan.hibernatetest.StationState#2]
4046 DEBUG [main] loader.Loader - Initializing object from ResultSet: [com.nathan.hibernatetest.StationState#2]
4046 DEBUG [main] entity.AbstractEntityPersister - Hydrating entity: [com.nathan.hibernatetest.StationState#2]
4046 DEBUG [main] type.LongType - returning '1' as column: station2_23_0_
4046 DEBUG [main] loader.Loader - done processing result set (1 rows)
4046 DEBUG [main] jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
4046 DEBUG [main] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
4046 DEBUG [main] jdbc.AbstractBatcher - closing statement
4046 DEBUG [main] loader.Loader - total objects hydrated: 1
4046 DEBUG [main] engine.TwoPhaseLoad - resolving associations for [com.nathan.hibernatetest.StationState#2]
4046 DEBUG [main] def.DefaultLoadEventListener - loading entity: [com.nathan.hibernatetest.Station#1]
4046 DEBUG [main] def.DefaultLoadEventListener - entity found in session cache
4046 DEBUG [main] engine.TwoPhaseLoad - done materializing entity [com.nathan.hibernatetest.StationState#2]
4046 DEBUG [main] loader.Loader - done entity load
4046 DEBUG [main] engine.TwoPhaseLoad - done materializing entity [com.nathan.hibernatetest.Station#1]
4046 DEBUG [main] engine.StatefulPersistenceContext - initializing non-lazy collections
4046 DEBUG [main] loader.Loader - done entity load
4046 DEBUG [main] loader.Loader - loading entity: [com.nathan.hibernatetest.StationState#com.nathan.hibernatetest.Station@691dee]
4046 DEBUG [main] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
4046 DEBUG [main] hibernate.SQL - select stationsta0_.stationstate_id as stations1_23_0_, stationsta0_.station_id as station2_23_0_ from nathan.stationstate stationsta0_ where stationsta0_.station_id=?
4046 DEBUG [main] jdbc.AbstractBatcher - preparing statement
4046 DEBUG [main] type.LongType - binding 'com.nathan.hibernatetest.Station@691dee' to parameter: 1
[/code]

_________________
nathan


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 03, 2005 11:28 am 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
No suggestions? This is a very simple test. Just call merge() on an object with a one-to-one relationship with another object (foreign key exists in the other object) in a new session.

Can someone who has used this type of relationship and been able to call merge() on the object just reply and say 'works for me', so I know it's my fault?

_________________
nathan


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 03, 2005 5:41 pm 
Regular
Regular

Joined: Fri Sep 09, 2005 11:35 am
Posts: 101
try removing property-ref. your mappings should work without it also.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 03, 2005 7:13 pm 
Expert
Expert

Joined: Wed Apr 06, 2005 5:03 pm
Posts: 273
Location: Salt Lake City, Utah, USA
Thanks for the reply.

I'm pretty sure the property-ref has to be there to tell Hibernate that it's not a one-to-one on a primary key, and which column is the foreign key.

I removed it in my test, and it no longer fails, but it behaves incorrectly. It tries to load stationstate by stationstate_id but uses the station_id value.

Quote:
3875 DEBUG [main] hibernate.SQL - select stationsta0_.stationstate_id as stations1_23_0_, stationsta0_.station_id as station2_23_0_ from nathan.stationstate stationsta0_ where stationsta0_.stationstate_id=?
Hibernate: select stationsta0_.stationstate_id as stations1_23_0_, stationsta0_.station_id as station2_23_0_ from nathan.stationstate stationsta0_ where stationsta0_.stationstate_id=?
3875 DEBUG [main] jdbc.AbstractBatcher - preparing statement
3875 DEBUG [main] type.LongType - binding '1' to parameter: 1
3875 DEBUG [main] jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
3875 DEBUG [main] loader.Loader - processing result set
3875 DEBUG [main] loader.Loader - done processing result set (0 rows)


I think the value is right, and the query where clause should be stationsta0.station_id=?

Anyway, I have submitted a bug in JIRA, and maybe they will help me resolve this. I won't rate you yet, but if it turns out to be my fault, and not a bug, I'll give you credit :)

_________________
nathan


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 09, 2005 5:14 pm 
Newbie

Joined: Wed Nov 09, 2005 5:10 pm
Posts: 1
For reference, the issue is:

http://opensource2.atlassian.com/projec ... e/HHH-1004

I posted some comments there as to the cause of the problem in the Hibernate
code. The workarounds would be:

A) Dont use merge() - but instead find() the existing entry and copy in
the changed data yourself.
B) Duplicate the data in the database so both sides are the "owning' side and
there is no inverse side with mappedBy.


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