-->
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: [Solved]Bi-directional one-to-one & Foreign key
PostPosted: Thu Feb 14, 2008 2:37 pm 
Newbie

Joined: Thu Feb 14, 2008 1:41 pm
Posts: 14
Hibernate version: 3.2.5.ga
Hibernate annotations version: 3.0.0.GA

This question has been asked many times on the forums, with one person even able to solve it, I've read the same solution at a few other places, but with little luck.
Using Spring for Hibernating properties and Data Source management.

User.java
Code:
public class User  {
  @Id @Column(name = "user_id")
  @GeneratedValue(strategy = GenerationType.AUTO)
  public Integer getUserId() { return userId; }
  public void setUserId(Integer userId) { this.userId = userId; }
  private Integer userId;
 
  @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @PrimaryKeyJoinColumn
  public Demographics getDemographics() { return demographics; }
  public void setDemographics(Demographics demographics) { this.demographics = demographics; }
  private Demographics demographics = new Demographics(); 

   // Other code...
}


Demographics.java
Code:
public class Demographics {

  // Trying to generate the key using foreign option
  @Id @Column(name = "user_id")
  @GeneratedValue(generator = "foreigner")
  @GenericGenerator(name = "foreigner", strategy = "foreign", parameters = { @Parameter(name = "property", value = "user") })
  public Integer getUserId() { return userId; }
  public void setUserId(Integer userId) { this.userId = userId; }
  private Integer userId; 

  @OneToOne (cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
  @PrimaryKeyJoinColumn
  public User getUser() { return user; }
  public void setUser(User user) { this.user = user; }
  private User user;
 
  // Other code
}


The Hibernate DB call is set as follows.

UserDAO.java
Code:
  User.getDemographics().setAddress("mars");
  getSessionFactory().getCurrentSession().saveOrUpdate(user); // Line 34


Now when this statement is run it gives the following error

Code:
org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property: user
   org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:44)
   org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:99)
   org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
   org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
   org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
   org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
   org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
   org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
   org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
   org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
   sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   java.lang.reflect.Method.invoke(Method.java:597)
   org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
   $Proxy22.save(Unknown Source)
   com.sourcemedia.dao.UserDAO.setUser(UserDAO.java:34)


Ok now since I have to use foreign to generate the key, I have to do a one-to-one mapping which needs to be bi-directional. (which I think using the cascade and @PrimaryKeyJoinColumn I've set them right). I went ahead to debug the code, it fails in org.hibernate.tuple.entity.AbstractEntityTuplizer when trying to retrieve the foreign key value from the User object mapped on Demographics.

The User object is inserted in the DB correctly and also retrieves an ID for that.
Code:
//Line 99  org.hibernate.event.def.AbstractSaveEventListener

Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity );


But in while getting the Properly value from the AbstractEntityTuplizer, it returns null.
Code:
org.hibernate.id.ForeignGenerator //Line 39

Object associatedObject = sessionImplementor.getFactory()
        .getClassMetadata( entityName )
        .getPropertyValue( object, propertyName, session.getEntityMode() );


On further investigation it was revealed that the User had Demographics, but the Demographics had User as null... So I investigated more on bi-directional one-to-one, also found does not seem to be a lazy issue, as one-to-one is not lazy.

The code works if the UserDAO is run this way.

UserDAO (modified)
Code:
    Session session = getSessionFactory().getCurrentSession();
    Transaction tx = session.beginTransaction();
    Demographics demographics = user.getDemographics();
    user.setDemographics(null);
    Integer id = (Integer)session.save(user);
    demographics.setUserId(id);
    session.save(demographics);
    tx.commit();


But we don't want this, we want hibernate to do the needful. Can someone point out where am I going wrong.

One more point adding the property (mappedBy = "userId") on the Demographics side gave an error trying to create the SessionFactory. So that also seems to be out...
Caused by: org.hibernate.AnnotationException: Referenced property not a (One|Many)ToOne: com.sourcemedia.pojo.User.userId in mappedBy of com.sourcemedia.pojo.Demographics.user

I read this link
http://opensource.atlassian.com/project ... e/HHH-2712
with further linking to...
http://www.i-proving.ca/space/Technolog ... ne+Mapping

Tried following this also
http://saloon.javaranch.com/cgi-bin/ubb ... 8&t=002219

But still my mapping crashes! any idea?


Last edited by varunmehta on Tue Feb 26, 2008 6:07 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Similar Post
PostPosted: Fri Feb 15, 2008 11:54 am 
Newbie

Joined: Thu Feb 14, 2008 1:41 pm
Posts: 14
http://forum.hibernate.org/viewtopic.php?t=983294


Top
 Profile  
 
 Post subject: Posted on the Spring Forum too
PostPosted: Tue Feb 26, 2008 4:02 pm 
Newbie

Joined: Thu Feb 14, 2008 1:41 pm
Posts: 14
In case anyone trying to find the solution, just adding links if solution received on Spring end.

http://forum.springframework.org/showthread.php?t=50390

Still haven't given up.

Interestingly the same configuration works for CaveatEmptor, using JPA/EJB3.0 but not with Spring... Refer spring forum for the complete application configuration files.


Top
 Profile  
 
 Post subject: No more Spring, not using HibernateUtil
PostPosted: Tue Feb 26, 2008 4:37 pm 
Newbie

Joined: Thu Feb 14, 2008 1:41 pm
Posts: 14
Picked up the HibernateUtil from the JPA example.

Error Trace
Code:
org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property: user
   at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:44)
   at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:98)
   at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
   at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
   at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:687)
   at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:669)
   at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
   at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
   at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
   at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
   at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
   at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:437)
   at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:194)
   at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
   at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
   at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
   at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
   at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
   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:597)
   at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
   at $Proxy13.merge(Unknown Source)
   at com.test.dao.UserDAO.setUser(UserDAO.java:15)
   at com.test.test.UserDAOTest.testDAO(UserDAOTest.java:36)
   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:597)
   at junit.framework.TestCase.runTest(TestCase.java:168)
   at junit.framework.TestCase.runBare(TestCase.java:134)
   at junit.framework.TestResult$1.protect(TestResult.java:110)
   at junit.framework.TestResult.runProtected(TestResult.java:128)
   at junit.framework.TestResult.run(TestResult.java:113)
   at junit.framework.TestCase.run(TestCase.java:124)
   at junit.framework.TestSuite.runTest(TestSuite.java:232)
   at junit.framework.TestSuite.run(TestSuite.java:227)
   at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81)
   at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
   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)


Info Log Trace
Code:
2008-02-26 15:31:22,274 INFO [org.hibernate.cfg.annotations.Version] - Hibernate Annotations 3.2.1.GA
2008-02-26 15:31:22,294 INFO [org.hibernate.cfg.Environment] - Hibernate 3.2.1
2008-02-26 15:31:22,299 INFO [org.hibernate.cfg.Environment] - hibernate.properties not found
2008-02-26 15:31:22,301 INFO [org.hibernate.cfg.Environment] - Bytecode provider name : cglib
2008-02-26 15:31:22,305 INFO [org.hibernate.cfg.Environment] - using JDK 1.4 java.sql.Timestamp handling
2008-02-26 15:31:22,421 INFO [org.hibernate.cfg.Configuration] - configuring from resource: /hibernate.cfg.xml
2008-02-26 15:31:22,421 INFO [org.hibernate.cfg.Configuration] - Configuration resource: /hibernate.cfg.xml
2008-02-26 15:31:22,678 INFO [org.hibernate.cfg.AnnotationConfiguration] - Mapping package com.test.pojo
2008-02-26 15:31:22,717 WARN [org.hibernate.cfg.AnnotationBinder] - Package not found or wo package-info.java: com.test.pojo
2008-02-26 15:31:22,723 INFO [org.hibernate.cfg.Configuration] - Configured SessionFactory: null
2008-02-26 15:31:22,788 INFO [org.hibernate.cfg.AnnotationBinder] - Binding entity from annotated class: com.test.pojo.User
2008-02-26 15:31:22,849 INFO [org.hibernate.cfg.annotations.EntityBinder] - Bind entity com.test.pojo.User on table user
2008-02-26 15:31:22,920 INFO [org.hibernate.cfg.AnnotationBinder] - Binding entity from annotated class: com.test.pojo.Demographic
2008-02-26 15:31:22,920 INFO [org.hibernate.cfg.annotations.EntityBinder] - Bind entity com.test.pojo.Demographic on table demographic
2008-02-26 15:31:23,059 INFO [org.hibernate.connection.DriverManagerConnectionProvider] - Using Hibernate built-in connection pool (not for production use!)
2008-02-26 15:31:23,059 INFO [org.hibernate.connection.DriverManagerConnectionProvider] - Hibernate connection pool size: 3
2008-02-26 15:31:23,060 INFO [org.hibernate.connection.DriverManagerConnectionProvider] - autocommit mode: true
2008-02-26 15:31:23,067 INFO [org.hibernate.connection.DriverManagerConnectionProvider] - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/chotatest?autoReconnect=true
2008-02-26 15:31:23,067 INFO [org.hibernate.connection.DriverManagerConnectionProvider] - connection properties: {user=root, password=****, autocommit=true}
2008-02-26 15:31:23,355 INFO [org.hibernate.cfg.SettingsFactory] - RDBMS: MySQL, version: 5.0.45-Debian_1ubuntu3.1-log
2008-02-26 15:31:23,355 INFO [org.hibernate.cfg.SettingsFactory] - JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.0.6 ( $Date: 2007-03-09 22:13:57 +0100 (Fri, 09 Mar 2007) $, $Revision: 6341 $ )
2008-02-26 15:31:23,372 INFO [org.hibernate.dialect.Dialect] - Using dialect: org.hibernate.dialect.MySQLInnoDBDialect
2008-02-26 15:31:23,378 INFO [org.hibernate.transaction.TransactionFactoryFactory] - Using default transaction strategy (direct JDBC transactions)
2008-02-26 15:31:23,381 INFO [org.hibernate.transaction.TransactionManagerLookupFactory] - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
2008-02-26 15:31:23,381 INFO [org.hibernate.cfg.SettingsFactory] - Automatic flush during beforeCompletion(): disabled
2008-02-26 15:31:23,381 INFO [org.hibernate.cfg.SettingsFactory] - Automatic session close at end of transaction: disabled
2008-02-26 15:31:23,381 INFO [org.hibernate.cfg.SettingsFactory] - JDBC batch size: 15
2008-02-26 15:31:23,381 INFO [org.hibernate.cfg.SettingsFactory] - JDBC batch updates for versioned data: disabled
2008-02-26 15:31:23,382 INFO [org.hibernate.cfg.SettingsFactory] - Scrollable result sets: enabled
2008-02-26 15:31:23,382 INFO [org.hibernate.cfg.SettingsFactory] - JDBC3 getGeneratedKeys(): enabled
2008-02-26 15:31:23,382 INFO [org.hibernate.cfg.SettingsFactory] - Connection release mode: auto
2008-02-26 15:31:23,383 INFO [org.hibernate.cfg.SettingsFactory] - Maximum outer join fetch depth: 3
2008-02-26 15:31:23,383 INFO [org.hibernate.cfg.SettingsFactory] - Default batch fetch size: 1
2008-02-26 15:31:23,383 INFO [org.hibernate.cfg.SettingsFactory] - Generate SQL with comments: enabled
2008-02-26 15:31:23,383 INFO [org.hibernate.cfg.SettingsFactory] - Order SQL updates by primary key: disabled
2008-02-26 15:31:23,383 INFO [org.hibernate.cfg.SettingsFactory] - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
2008-02-26 15:31:23,385 INFO [org.hibernate.hql.ast.ASTQueryTranslatorFactory] - Using ASTQueryTranslatorFactory
2008-02-26 15:31:23,386 INFO [org.hibernate.cfg.SettingsFactory] - Query language substitutions: {}
2008-02-26 15:31:23,386 INFO [org.hibernate.cfg.SettingsFactory] - JPA-QL strict compliance: disabled
2008-02-26 15:31:23,386 INFO [org.hibernate.cfg.SettingsFactory] - Second-level cache: enabled
2008-02-26 15:31:23,394 INFO [org.hibernate.cfg.SettingsFactory] - Query cache: disabled
2008-02-26 15:31:23,394 INFO [org.hibernate.cfg.SettingsFactory] - Cache provider: org.hibernate.cHibernate: ache.NoCacheProvider
2008-02-26 15:31:23,395 INFO [org.hibernate.cfg.SettingsFactory] - Optimize cache for minimal puts: disabled
2008-02-26 15:31:23,395 INFO [org.hibernate.cfg.SettingsFactory] - Structured second-level cache entries: disabled
2008-02-26 15:31:23,400 INFO [org.hibernate.cfg.SettingsFactory] - Echoing all SQL to stdout
2008-02-26 15:31:23,401 INFO [org.hibernate.cfg.SettingsFactory] - Statistics: disabled
2008-02-26 15:31:23,401 INFO [org.hibernate.cfg.SettingsFactory] - Deleted entity synthetic identifier rollback: disabled
2008-02-26 15:31:23,402 INFO [org.hibernate.cfg.SettingsFactory] - Default entity-mode: pojo
2008-02-26 15:31:23,449 INFO [org.hibernate.impl.SessionFactoryImpl] - building session factory
2008-02-26 15:31:23,775 INFO [org.hibernate.impl.SessionFactoryObjectFactory] - Not binding factory to JNDI, no JNDI name configured
2008-02-26 15:31:23,785 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - Running hbm2ddl schema export
2008-02-26 15:31:23,786 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - exporting generated schema to database
2008-02-26 15:31:23,856 INFO [org.hibernate.tool.hbm2ddl.SchemaExport] - schema export complete
Hibernate:
    /* insert com.test.pojo.User
        */ insert
        into
            user
            (username, password, name, created)
        values
            (?, ?, ?, ?)



*********** THIS PART ON FROM DEBUG************



2008-02-26 15:34:06,864 DEBUG [com.test.data.HibernateUtil] - Hibernate initialized, call HibernateUtil.getSessionFactory()
2008-02-26 15:34:06,942 DEBUG [org.hibernate.impl.SessionImpl] - opened session at timestamp: 12040580469
2008-02-26 15:34:07,030 DEBUG [org.hibernate.transaction.JDBCTransaction] - begin
2008-02-26 15:34:07,030 DEBUG [org.hibernate.jdbc.ConnectionManager] - opening JDBC connection
2008-02-26 15:34:07,031 DEBUG [org.hibernate.transaction.JDBCTransaction] - current autocommit status: true
2008-02-26 15:34:07,031 DEBUG [org.hibernate.transaction.JDBCTransaction] - disabling autocommit
2008-02-26 15:34:07,050 DEBUG [org.hibernate.event.def.AbstractSaveEventListener] - executing identity-insert immediately
2008-02-26 15:34:07,051 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2008-02-26 15:34:07,054 DEBUG [org.hibernate.SQL] -
    /* insert com.test.pojo.User
        */ insert
        into
            user
            (username, password, name, created)
        values
            (?, ?, ?, ?)
Hibernate:
    /* insert com.test.pojo.User
        */ insert
        into
            user
            (username, password, name, created)
        values
            (?, ?, ?, ?)
2008-02-26 15:34:07,079 DEBUG [org.hibernate.id.IdentifierGeneratorFactory] - Natively generated identity: 1
2008-02-26 15:34:07,079 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)


So does not seem to be a problem with Spring...


Top
 Profile  
 
 Post subject: The Solution
PostPosted: Tue Feb 26, 2008 6:11 pm 
Newbie

Joined: Thu Feb 14, 2008 1:41 pm
Posts: 14
The solution was setting the user back on demographic!

UserDAOTest
Code:
  public void testDAO() {
    IUserDao userDAO = (IUserDao)getApplicationContext().getBean("userDAO");
    User user = new User();
    user.setName("Clark Kent");
    user.setPassword("kryptonite");
    user.setUsername(RandomStringUtils.randomAlphabetic(10));
    // create demographics object
    Demographic demographic = new Demographic();
    demographic.setAddress("daily planet");
    demographic.setCity(RandomStringUtils.randomAlphabetic(10));
    demographic.setState("NY");
    demographic.setCountry("US");
    user.setDemographic(demographic);
    demographic.setUser(user);
    // Save the user to database
    userDAO.setUser(user);
  }


Got the clue from here.
http://forum.hibernate.org/viewtopic.ph ... beb438a433

Ok it sounds a bit too tacky to set the parent object on the child object too, but then we are doing a Bi-directional mapping so it does make sense too..

Looks like it's finally solved...


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.