-->
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.  [ 8 posts ] 
Author Message
 Post subject: 5.1.2.4. Partial identifier generation
PostPosted: Tue Nov 09, 2010 3:48 pm 
Newbie

Joined: Tue Nov 09, 2010 3:08 pm
Posts: 6
My question comes from section 5.1.2.4. Partial identifier generation.

The reference manual states:
Quote:
You can also generate properties inside an @EmbeddedId class.


That is what I want to do.

I have a table as follows:

Code:
CREATE TABLE gen_test (
  rateno     VARCHAR(20) NOT NULL,
  ratefiltno numeric(20) identity NOT NULL
)

ALTER TABLE gen_test
  ADD CONSTRAINT gen_test_pk PRIMARY KEY (
    ratefiltno,
    rateno
)


Here is the entity and it's id:
Code:
@Entity()
@Table(name="GEN_TEST")
@Proxy(lazy = false)
public class GenTest extends AbstractPersistent<GenTest> implements java.io.Serializable {
   
    private GenTestId id;

    @EmbeddedId   
    @AttributeOverrides( {
        @AttributeOverride(name="ratefiltno", column=@Column(name="RATEFILTNO", nullable=false, precision=20, scale=0) ),
        @AttributeOverride(name="rateno", column=@Column(name="RATENO", nullable=false, length = 20) ) } )
    public GenTestId getId() {
        return this.id;
    }
   
    public void setId(GenTestId id) {
        this.id = id;
    }

    // define equals and hashCode

}


@Embeddable
public class GenTestId implements java.io.Serializable {

   private Integer ratefiltno;
   private String rateno;

   public GenTestId() {
   }

   public GenTestId(Integer ratefiltno, String rateno) {
      this.ratefiltno = ratefiltno;
      this.rateno = rateno;
   }

   @Column(name = "RATEFILTNO", nullable = false, precision=20, scale=0)
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }

   public void setRatefiltno(Integer ratefiltno) {
      this.ratefiltno = ratefiltno;
   }

   @Column(name = "RATENO", nullable = false, length = 20)
   public String getRateno() {
      return rateno;
   }

   public void setRateno(String rateno) {
      this.rateno = rateno;
   }

   // define equals and hashCode

}




I want to be able to insert rateNo by manually assigning it and ratefiltno using a identity generator. I try to insert after populating the entity as such:
Code:
       GenTest entity = getBean(GenTest.class);
       GenTestId id = new GenTestId();
       id.setRateno("9");
       entity.setId(id);
       getHibernateTemplate().saveOrUpdate(entity);


I am connecting to a SQL Server database. I have this working when there is no rateNo column. I am using Spring and the above code is being executed in a method marked @Transactional. Thus, the saveOrUpdate() is occurring in a transaction. I believe this is required? I get the exception:
Code:
ERROR [main] (JDBCExceptionReporter.java:234) - Cannot insert explicit value for identity column in table 'gen_test' when IDENTITY_INSERT is set to OFF.
ERROR [main] (AbstractFlushingEventListener.java:324) - Could not synchronize database state with session
org.hibernate.exception.SQLGrammarException: could not insert: [com.geowareinc.finance.rate.models.GenTest]
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2436)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2856)
        at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
        at com.geowareinc.common.persistent.ChainedTransactionManager.commit(ChainedTransactionManager.java:76)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
        at com.geowareinc.transactionalservice.etl.persistent.TransactionalService$$EnhancerByCGLIB$$86a6373b.testSave(<generated>)
        at com.geowareinc.transactionalservice.etl.persistent.TransactionalServiceTest.testSave(TransactionalServiceTest.java:23)
        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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
        at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
        at junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.java:39)
        at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:518)
        at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1052)
        at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:906)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert explicit value for identity column in table 'gen_test' when IDENTITY_INSERT is set to OFF.
        at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:197)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1493)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:390)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:340)
        at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4575)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1400)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:179)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:154)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:308)
        at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
        at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
        at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46)
        at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2416)


I did a google search for:

Code:
Cannot insert explicit value for identity column in table 'gen_test' when IDENTITY_INSERT is set to OFF


and found that I should run this in SQL Server Management Studio:
Code:
SET IDENTITY_INSERT gen_test ON;

but that did nothing.

Any help would be very appreciated.


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Thu Nov 11, 2010 9:44 pm 
Newbie

Joined: Tue Nov 09, 2010 3:08 pm
Posts: 6
I found a solution! I don't use a separate class for the identifier and it works! But for some reason the identity generator didn't work. I used an increment generator instead. Here is GenTest:
Code:
public class GenTest extends AbstractPersistent<GenTest> {

   @Id
   @Column(name = "RATEFILTNO", nullable = false, precision=20, scale=0)
   @GeneratedValue(generator="inc-gen")
   @GenericGenerator(name="inc-gen", strategy = "increment")
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }

   public void setRatefiltno(Integer ratefiltno) {
      this.ratefiltno = ratefiltno;
   }

   @Id
   @Column(name = "RATENO", nullable = false, length = 20)
   public String getRateno() {
      return rateno;
   }

   public void setRateno(String rateno) {
      this.rateno = rateno;
   }

   // implement equals and hashCode methods


The DDL script to create gen_test changes to:
Code:
CREATE TABLE gen_test (
  rateno     VARCHAR(20) NOT NULL,
  ratefiltno numeric(20) NOT NULL
)


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Tue Nov 16, 2010 5:01 am 
Newbie

Joined: Fri Nov 13, 2009 4:16 am
Posts: 3
aaronw wrote:
I found a solution! I don't use a separate class for the identifier and it works! But for some reason the identity generator didn't work. I used an increment generator instead.


What do you mean by "the identity generator didn't work"?


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Tue Nov 16, 2010 9:07 am 
Newbie

Joined: Tue Nov 09, 2010 3:08 pm
Posts: 6
I was referring to the generator strategy. The following did not work, it is using the identity strategy:
Code:
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }

but this did work, it is using the increment strategy:
Code:
   @GeneratedValue(generator="inc-gen")
   @GenericGenerator(name="inc-gen", strategy = "increment")
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Tue Nov 16, 2010 9:17 am 
Newbie

Joined: Tue Nov 09, 2010 3:08 pm
Posts: 6
I still would love to find a solution for the first post. That is, using a generator within an @Embeddable class. Hibernate seems to work better using identifiers that are component type. The be clear here is how Hibernate describes such identifiers:
Quote:
You can define a composite primary key through several syntaxes: use a component type to represent the identifier and map it as a property in the entity: you then annotated the property as @EmbeddedId. The component type has to be Serializable.


By Hibernate seems to work better I mean with relationships between entities.


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Mon Nov 22, 2010 5:39 am 
Newbie

Joined: Fri Nov 13, 2009 4:16 am
Posts: 3
aaronw wrote:
I was referring to the generator strategy. The following did not work, it is using the identity strategy:
Code:
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }

but this did work, it is using the increment strategy:
Code:
   @GeneratedValue(generator="inc-gen")
   @GenericGenerator(name="inc-gen", strategy = "increment")
   public Integer getRatefiltno() {
      return this.ratefiltno;
   }


Indeed, partial key generation doesn't work if hibernate needs to refresh the value of the key from database. I tested with a trigger and a sequence on oracle database and didn't work. Actually documentation makes it very clear (http://docs.jboss.org/hibernate/core/3. ... ompositeid)

"You cannot use an IdentifierGenerator to generate composite keys. Instead the application must assign its own identifiers."


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Mon Nov 22, 2010 5:43 am 
Newbie

Joined: Fri Nov 13, 2009 4:16 am
Posts: 3
aaronw wrote:
I still would love to find a solution for the first post. That is, using a generator within an @Embeddable class. Hibernate seems to work better using identifiers that are component type. The be clear here is how Hibernate describes such identifiers:
Quote:
You can define a composite primary key through several syntaxes: use a component type to represent the identifier and map it as a property in the entity: you then annotated the property as @EmbeddedId. The component type has to be Serializable.


By Hibernate seems to work better I mean with relationships between entities.


Myself I gave up with composite key (it is risky, since is not a very supported scenario with hibernate). Do you really need to map with composite key, do you have a legacy database?


Top
 Profile  
 
 Post subject: Re: 5.1.2.4. Partial identifier generation
PostPosted: Mon Nov 22, 2010 9:31 am 
Newbie

Joined: Tue Nov 09, 2010 3:08 pm
Posts: 6
Hibernate 3.6 added support for partial identifier generation. So you can have a composite identifier and use a generator. Read my previous posts and see section 5.1.2.4. Partial identifier generation.


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