-->
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.  [ 3 posts ] 
Author Message
 Post subject: Using Postgres Id Generator and Composite primary key.
PostPosted: Thu Sep 04, 2008 11:10 am 
Newbie

Joined: Thu Sep 04, 2008 10:55 am
Posts: 1
Location: Venezuela
Hibernate version: 3.2.5
Hibernate-Annotations: 3.3.1GA
PostgreSQL: 8.2


I have been trying to create a class (tipoSubestacion) and do it persistent in a table of Postgres (tipo_subestacion) whose is composed by a primary key which formed by two columns: mandt and id, being the id column autogenerated as a sequence in Postgress and mandt is a foreing key.

So far, it has not been possible to create a record in the table whose id is auto generated, hibernate shows a message of Violation of Constraint because doesn’t generate the id, it only put null at id. Otherwise when I set a value on id, hibernate save the data without problems.

The error message is: “java.sql.BatchUpdateException: Batch entry 0 insert into pm.tipo_subestacion (de_tipo_subestacion, id_tipo_subestacion, co_mandt) values (Electromecanica, NULL, 210) was aborted. ”

My question is, it is possible create a compose primary key when one of those is an auto generate column, if it is possible, how?

Here is the tipoSubestacion object with its Annotations:



Code:
@Entity
@IdClass(TipoSubestacionPK.class)

@Table(name="tipo_subestacion", schema="pm"
      ,uniqueConstraints={@UniqueConstraint(columnNames={"co_mandt","id_tipo_subestacion"})})
public class TipoSubestacion implements ITipoSubestacion 
{
    @EmbeddedId private Long id;
   
   private IMandante mandante;
   
   
   private String descripcion;
   
   
   public TipoSubestacion() {}
   
   public TipoSubestacion( IMandante mandante, String descripcion )
   {
       this.descripcion  = descripcion;   
      this.mandante    = mandante;
   }
   
   public TipoSubestacion( Long id, IMandante mandante, String descripcion )
   {
       this.id = id;
      this.descripcion  = descripcion;   
      this.mandante    = mandante;
   }

   @Id
   public Long getId()
   {
      return this.id;
   }

   public ITipoSubestacion setId( Long id )
   {
       this.id = id;      
      return this;
   }
   
   @Id
   public IMandante getMandante()
   {
      return this.mandante;
   }

   public ITipoSubestacion setMandante( IMandante mandante )
   {
      this.mandante = mandante;
      
      return this;
   }
   
   @Column( name = "de_tipo_subestacion", columnDefinition = "VARCHAR(25)")      
   public String getDescripcion()
   {
      return this.descripcion;
   }

   public ITipoSubestacion setDescripcion(String descripcion )
   {
      this.descripcion = descripcion;
      return this;
   }      
}



Here is the tipoSubestacionPK object with its Annotations:

Code:
@Embeddable
@javax.persistence.SequenceGenerator(
      name="SEQ_GEN",
      sequenceName="pm.tipo_subestacion_id_tipo_subestacion_seq",
      allocationSize=1
      )
public class TipoSubestacionPK implements ITipoSubestacionPK, Serializable
{

   private IMandante mandante = null;
   
   private Long id = null;
   
   //ITipoSubestacion is the interface of TipoSubestacion
   private ITipoSubestacion tipoSub;
   
   public TipoSubestacionPK(){}
   
   public TipoSubestacionPK(IMandante mandante)
   {
      this.mandante   = mandante;
   }
   
   public TipoSubestacionPK(IMandante mandante, Long id )
   {
      this.mandante   = mandante;
      this.id  = id;
   }
   
   @Valid
   @ManyToOne(targetEntity=Mandante.class, fetch = FetchType.LAZY)
   @JoinColumn(name = "co_mandt", nullable = false, insertable = true, updatable = true)
   public IMandante getMandante()
   {
      return this.mandante;
   }

   public ITipoSubestacionPK setMandante(IMandante mandante)
   {
      this.mandante = mandante;
      return this;
   }
   
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
   @Column( name = "id_tipo_subestacion", columnDefinition = "INTEGER")
   public Long getId()
   {
      return this.id;
   }

   public ITipoSubestacionPK setId(Long id)
   {
      this.id = id;
      return this;
   }
   
   @OneToOne(mappedBy="tipo_subestacion")
   public ITipoSubestacion getTipoSubestacion()
   {
      return tipoSub;
   }
   
}



And here is the definition of the PostgreSQL sequence, according to pgAdmin:
CREATE SEQUENCE pm.tipo_subestacion_id_tipo_subestacion_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 2
CACHE 1;
ALTER TABLE pm.tipo_subestacion_id_tipo_subestacion_seq OWNER TO postgres;




Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 11, 2008 4:06 am 
Hibernate Team
Hibernate Team

Joined: Thu Apr 05, 2007 5:52 am
Posts: 1689
Location: Sweden
Hi,

It seems you are mixing the strategies you have to define the composite key. You have to use one of these strategies:
* annotate the component property as @Id and make the component class @Embeddable
* annotate the component property as @EmbeddedId
* annotate the class as @IdClass and annotate each property of the entity involved in the primary key with @Id

The @EmbeddedId in TipoSubestacion is useless.

In spite of this I think you cannot use a sequence generator in a composite key situation.

--Hardy


Top
 Profile  
 
 Post subject: Composite ID Generator
PostPosted: Thu Sep 18, 2008 7:02 am 
Beginner
Beginner

Joined: Thu Jun 30, 2005 4:20 am
Posts: 40
Location: Vienna
Hi,

here is a solution where you can use a sequence generator with a composite key. It has some prerequisites - see the Javadoc in the code.

Note that currently this extends my own "simple" generator class, but if you let it extend a SequenceGenerator it should also work (though I haven't tested this)

regards
Stefan


Code:
package at.rsf4j.core.db.hibernate.util;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.LongType;
import org.hibernate.type.Type;

import at.rsf4j.core.log.RSFLoggerIF;
import at.rsf4j.core.system.RSFFrameworkManager;

/**
* This extends the RSFHibernateIdGenerator with the possibility to create IDs for composite primary keys.
* The requirements for these composite keys are:
*
* <ul>
* <li> The composite primary key is modelled as a separate primary key class, and mapped
* in the mapping file as &lt;composite-id&gt;
*
* <li> The composite key must contain one synthetic Long variable with a corresponding setter method that takes a Long parameter.
* This is the variable that will be incremented automatically.
*
* <li> The composite key can contain any number of other values, which must be set manually by the programmer.
*
* <li> Before inserting a Hibernate object, the composite key object has to be saved to the Hibernate object, but the
* synthetic variable of the composite key must be null (or will be overwritten)
*
* <li> The composite key object must correctly implement equals()/hashCode().
* See "Java Persistence with Hibernate", page 327 for details. 
*
* <li> The generator needs two additional properties:
*
* a) compositePrimaryKeyGetter: the name of the getter Method for the composite primary key, in the Hibernate Bean class
*
* b) syntheticKeySetter: the name of the setter Method of the synthetic key, in the Primary Key classs
* </ul>
* example for a mapping file with a composite ID generator:
*
* <hr><blockquote><pre>
*   &lt;class name="at.rzb.ccn.bl.hbm.generated.Tgrccust" table="TGRCCUST"&gt;
*     &lt;composite-id name="comp_id" class="at.rzb.ccn.bl.hbm.generated.TgrccustPK"&gt;
*       &lt;key-property name="ccustId" column="CCUST_ID" type="java.lang.Long" length="22"&gt;
*       &lt;/key-property&gt;
*       &lt;key-property name="ccustDatRep" column="CCUST_DAT_REP" type="java.sql.Timestamp" length="7"&gt;
*       &lt;/key-property&gt;
*       &lt;generator class="at.rsf4j.core.db.hibernate.util.RSFHibernateCompositeIdGenerator"&gt;
*          &lt;param name="compositePrimaryKeyGetter"&gt;getComp_id&lt;/param&gt;
*          &lt;param name="syntheticKeySetter"&gt;setCcustId&lt;/param&gt;
*       &lt;/generator&gt;
*     &lt;/composite-id&gt;
* </pre></blockquote><hr>
*
* @author wzbmsf
*/
public class RSFHibernateCompositeIdGenerator extends RSFHibernateIdGenerator {
   public static final String COMPOSITE_PRIMARY_KEY_GETTER_PARAM = "compositePrimaryKeyGetter";
   public static final String SYNTHETIC_KEY_SETTER_PARAM = "syntheticKeySetter";
   private static final RSFLoggerIF LOG = RSFFrameworkManager.getLogger(RSFHibernateCompositeIdGenerator.class);
   
   private String compositePrimaryKeyGetter;
   private String syntheticKeySetter;

   
   /**
    * generates the ID.
    * This just calls the super class, which returns a Long value. This long value
    * will then be written to the synthetic part of the primary key object.
    */
   public Serializable generate(SessionImplementor session, Object mappedBean) throws HibernateException
   {
      try
      {
         //Let the superclass generate the ID
         Serializable idSer = super.generate(session, mappedBean);
         
         //now write the generated ID to the composite primary key
         Long generatedId = (Long)idSer;
         
         LOG.debug ("generated ID " + generatedId + " for class:" + mappedBean.getClass().getName());
         //read the composite primary key from the mapped Java Bean, e.g.: TgrccustPK pk = ccust.getComp_id(); 
         Method methodGetPrimaryKey = mappedBean.getClass().getMethod(getCompositePrimaryKeyGetter(), null);
         Object primaryKey = methodGetPrimaryKey.invoke(mappedBean, null);
         
         //set the generated ID in the composite primary key, e.g. pk.setCcustId()
         Method methodSetSyntheticKeyInCompositeKey = primaryKey.getClass().getMethod(getSyntheticKeySetter(), new Class[]{Long.class});
         methodSetSyntheticKeyInCompositeKey.invoke(primaryKey, new Object[]{generatedId});
         
         return (Serializable)primaryKey;
      }
      catch (SecurityException e)
      {
         throw new HibernateException("cannot read primary key of mapped class", e);
      }
      catch (NoSuchMethodException e)
      {
         throw new HibernateException("cannot find method", e);
      }
      catch (IllegalArgumentException e)
      {
         throw new HibernateException("cannot find parameter", e);
      }
      catch (IllegalAccessException e)
      {
         throw new HibernateException("could not access method", e);
      }
      catch (InvocationTargetException e)
      {
         throw new HibernateException(e);
      }
   }

   /**
    * configure the Composite ID generator
    * @param type will be ignored; the generated ID will always be a Long
    * @param params params for the generator
    * @param dialect the DB dialect
    */
   public void configure(Type type, Properties params, Dialect dialect) throws MappingException
   {
      //we want the generator to generate a long, not a composite type
      Type longTypeForGenerator = new LongType();
      super.configure(longTypeForGenerator, params, dialect);
      
      
      String compositePrimaryKeyGetter = (String)params.get(COMPOSITE_PRIMARY_KEY_GETTER_PARAM);
      String syntheticKeySetter = (String)params.get(SYNTHETIC_KEY_SETTER_PARAM);
   
      if (compositePrimaryKeyGetter == null)
      {
         throw new MappingException("missing parameter for CompositeIdGenerator: " + COMPOSITE_PRIMARY_KEY_GETTER_PARAM);
      }
      if (syntheticKeySetter == null)
      {
         throw new MappingException("missing parameter for CompositeIdGenerator: " + SYNTHETIC_KEY_SETTER_PARAM);
      }
      
      setCompositePrimaryKeyGetter(compositePrimaryKeyGetter);
      setSyntheticKeySetter(syntheticKeySetter);
   }
   /**
    * @return Returns the compositePrimaryKeyGetter.
    */
   protected String getCompositePrimaryKeyGetter()
   {
      return compositePrimaryKeyGetter;
   }
   /**
    * @param compositePrimaryKeyGetter The compositePrimaryKeyGetter to set.
    */
   protected void setCompositePrimaryKeyGetter(String getPrimaryKeyMethod)
   {
      this.compositePrimaryKeyGetter = getPrimaryKeyMethod;
   }
   /**
    * @return Returns the syntheticKeySetter.
    */
   protected String getSyntheticKeySetter()
   {
      return syntheticKeySetter;
   }
   /**
    * @param syntheticKeySetter The syntheticKeySetter to set.
    */
   protected void setSyntheticKeySetter(String setSyntheticKeyMethod)
   {
      this.syntheticKeySetter = setSyntheticKeyMethod;
   }
}


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