- 
        1. Re: EmbeddedId and GeneratedValuebill.burke Mar 3, 2006 4:29 PM (in response to nholbrook)id generation is not supported/required by the specification for composite keys. 
 I do suggest you log a feature request and bug on www.hibernate.org
 feature request: to allow generated values for composite id properties
 bug report: to get a clearer error message.
- 
        
- 
        3. Re: EmbeddedId and GeneratedValuenholbrook Mar 6, 2006 5:30 PM (in response to nholbrook)Well, I did some digging around and came up with an interim solution that seems to work pretty well. I have multiple databases so I picked my common module to manage autogenerated id's for compount primary keys. The first is the entity object I generated in the database. The second is the IDGenerator class for my composite-id entity objects. The third is the basic logic behind the generator. Anyway, I just thought I'd post this since there isn't a lot of information out there on GenericGenerators. If I have something bad in here, let me know... 
 Thanks
 Nic
 ------------------------------------- Entity on the table that manages the id's -----------------------------
 @Entity
 @Table(name="sec_uuid")
 public class SecUUID implements java.io.Serializable
 {
 private String entity;
 private Long value;
 public SecUUID()
 {
 }
 public SecUUID(String entity, Long value)
 {
 this.entity = entity;
 this.value = value;
 }
 @Id
 @Column(name="entity", unique = true, nullable = false, insertable = true, updatable = true, length = 45)
 public String getEntity()
 {
 return entity;
 }
 public void setEntity(String entity)
 {
 this.entity = entity;
 }
 @Column(name="value", unique = false, nullable = true, insertable = true, updatable = true)
 public Long getValue()
 {
 return value;
 }
 public void setValue(Long value)
 {
 this.value = value;
 }
 }
 --------------------------------------- Id generator class -------------------------------------------
 /**
 *
 * The following is an example annotation to be used on the class declaration of the entity.
 * Column name(In this case customerId) is the name of the property inside the embedded id that needs to be auto-incremented.
 * The column also needs to be of type Long.
 * @GenericGenerator(name = "KeyGenerator", strategy = "EmbeddedIDGenerator",
 * parameters = {
 * @Parameter (name=EmbeddedIDGenerator.COLUMN_NAME, value="customerId")
 * }
 * )
 *
 *
 * The following is the tag that needs to put on the Id field of the entity. This field must
 * be an embedded id and the name must be id.
 * @GeneratedValue(generator = "KeyGenerator")
 */
 public class EmbeddedIDGenerator
 implements IdentifierGenerator, Configurable
 {
 private static final Log log = LogFactory.getLog(EmbeddedIDGenerator.class);
 public static final String COLUMN_NAME = "uuid_column";
 private String entityName;
 private String columnName;
 public Serializable generate(SessionImplementor sessionImplementor, Object arg1)
 throws HibernateException
 {
 log.debug("Generating id for entity " + entityName);
 Object entity = arg1;
 try
 {
 log.debug("Working on entity " + entity.getClass().getName());
 Serializable key = (Serializable)PropertyUtils.getProperty(entity, "id");
 log.debug("I have key for entity " + key.getClass().getName());
 log.debug("Looking up the next uuid for key " + key);
 // This is where you will make a call or execute sql to get your next id.
 Long id = ProxyFactory.getProxy().getNextUUID(entityName);
 log.debug("Setting the value " + id + " on property " + columnName);
 PropertyUtils.setProperty(key, columnName, id);
 return key;
 }
 catch (IllegalAccessException e)
 {
 log.error(e);
 throw new TessRuntimeException("There was an error generating the id for " + entityName);
 }
 catch (InvocationTargetException e)
 {
 log.error(e);
 throw new TessRuntimeException("There was an error generating the id for " + entityName + ". Key must have a setter for column " + columnName);
 }
 catch (NoSuchMethodException e)
 {
 log.error(e);
 throw new TessRuntimeException("There was an error generating the id for " + entityName + ". Entity must have a getId() method.");
 }
 }
 public void configure(Type type, Properties properties, Dialect dialect)
 throws MappingException
 {
 entityName = properties.getProperty(ENTITY_NAME);
 columnName = properties.getProperty(COLUMN_NAME);
 }
 }
 ---------------------------------------------------------- UUID Generation Logic --------------
 public Long getNextUUID(String entityName)
 {
 String QUERY = "from SecUUID as uuid where uuid.entity = :entityName";
 SecUUID uuid;
 try
 {
 log.debug("Looking up entity " + entityName);
 uuid = (SecUUID)pm.getEntityManager().createQuery(QUERY).setParameter("entityName", entityName).getSingleResult();
 uuid.setValue(uuid.getValue() + 1L);
 log.debug("Incrementing the uuid by 1");
 log.debug("updating value to " + uuid.getValue());
 pm.getEntityManager().flush();
 return uuid.getValue();
 }
 catch (NoResultException e)
 {
 log.debug("No uuid fond for entity " + entityName);
 pm.insert(new SecUUID(entityName, 1L));
 log.debug("Inserted entry for " + entityName);
 return 1L;
 }
 }
 -------------------------------- Example Entity -------------------------------------
 @Entity
 @GenericGenerator(name = "KeyGenerator", strategy = "com.bla.util.EmbeddedIDGenerator",
 parameters = {
 @Parameter (name=EmbeddedIDGenerator.COLUMN_NAME, value="customerId")
 })
 @Table(name = "customer", catalog = "tescsm", uniqueConstraints = {})
 public class Customer
 {
 @EmbeddedId
 @GeneratedValue(generator = "KeyGenerator")
 @AttributeOverrides( {
 @AttributeOverride(name = "customerId", column = @Column(name = "customer_id", unique = false, nullable = false, insertable = true, updatable = true)),
 @AttributeOverride(name = "carrierId", column = @Column(name = "carrier_id", unique = false, nullable = false, insertable = true, updatable = true))})
 public CustomerId getId()
 {
 return this.id;
 }
 }
 -------------------------------------- Embeddable Id ------------------------------
 @Embeddable
 public class CarrierCustomerId
 implements java.io.Serializable
 {
 // Fields
 private Long customerId;
 private Integer carrierId;
 // Constructors
 /** default constructor */
 public CarrierCustomerId()
 {
 }
 /** full constructor */
 public CarrierCustomerId(Long customerId, Integer carrierId)
 {
 this.customerId = customerId;
 this.carrierId = carrierId;
 }
 // Property accessors
 @Column(name = "customer_id", unique = true, nullable = false, insertable = true, updatable = true)
 @GeneratedValue
 public Long getCustomerId()
 {
 return this.customerId;
 }
 public void setCustomerId(Long customerId)
 {
 this.customerId = customerId;
 }
 @Column(name = "carrier_id", unique = false, nullable = false, insertable = true, updatable = true)
 public Integer getCarrierId()
 {
 return this.carrierId;
 }
 public void setCarrierId(Integer carrierId)
 {
 this.carrierId = carrierId;
 }
 }
- 
        4. Re: EmbeddedId and GeneratedValuesquishy Mar 31, 2006 7:24 AM (in response to nholbrook)I think it's surprising that there's so little about composite primary keys with auto generated values yet.. 
 Isn't it also possible that, evertime you add a new entry to the database you do a query like (Role is the entity i tried with)"SELECT MAX(r.roleId) + 1 FROM Role r" 
 and take it as the ID?
 I don't like it this way, because the code isnt in the entity itself, but i prefer it over creating a whole new table for primary keys, which doesn't appear very clean to me...
 Isn't there a proper implementation for @GeneratedValue by the container/hibernate yet??
- 
        5. Re: EmbeddedId and GeneratedValueepbernard Mar 31, 2006 7:36 AM (in response to nholbrook)your solution can be very inefficient and conceptually does not work. you need to think about concurrent transactions. 
- 
        6. Re: EmbeddedId and GeneratedValuesquishy Apr 1, 2006 6:04 AM (in response to nholbrook)i thoguht so. do you have an idea for working solution? i'd be very thankful :) 
- 
        7. Re: EmbeddedId and GeneratedValueepbernard Apr 3, 2006 5:53 AM (in response to nholbrook)the one provided by the spec :-) 
 TABLE is very efficient, clean and respectful of your Tx concurrency.
- 
        8. Re: EmbeddedId and GeneratedValuesquishy Apr 3, 2006 5:54 AM (in response to nholbrook)uh, there is one? tried several things with @GeneratedValue Annotation, but the only id i got generated was 0 :o 
- 
        9. Re: EmbeddedId and GeneratedValuesquishy Apr 3, 2006 7:12 AM (in response to nholbrook)(the class has @IdClass with appropriate PK-class) @Id @GeneratedValue(strategy=GenerationType.TABLE) public int getUserId() { return userId; }
 leads to a
 java.sql.BatchUpdateException: failed batch
 on the 2nd insert into the database.
 1 Entity is wrote to the database, its Id is 0.
 is this how it is supposed to be? :o
- 
        10. Re: EmbeddedId and GeneratedValueepbernard Apr 3, 2006 12:42 PM (in response to nholbrook)check the test suites this definitely works. 
 If you don't use DDL generation, you'll have to create the increment table yourself before running the app
- 
        11. Re: EmbeddedId and GeneratedValuesquishy Apr 3, 2006 4:44 PM (in response to nholbrook)apparently hibernate does not create an entry in HIBERNATE_SEQUENCES for my Bean with the PK class, but for the same one without pk class.. 
 Uhm.. can you give me a hint on how to find a test suit that tests this.. ? (no clue of them test suits :o)
- 
        12. Re: EmbeddedId and GeneratedValuesquishy Apr 5, 2006 3:09 AM (in response to nholbrook)I tested the same beans with new Jboss 4.0.4CR2 + EJB3CR6, the only thing that's different is that i get no errors, because the row with id 0 is simply overridden by each new entity that is added to the database. (no errors there!) 
 No HIBERNATE_SEQUENCES table is created either.
 Could you be so kind to show me a working example? (or point me to where i find one :)
 im totally lost here..
- 
        13. Re: EmbeddedId and GeneratedValuesquishy Apr 5, 2006 3:16 AM (in response to nholbrook)just realized the overiding happens because i used manager.merge instead of manager.persist . 
 Doesn't solve my problem though..
- 
        14. Re: EmbeddedId and GeneratedValuesquishy Apr 5, 2006 3:16 PM (in response to nholbrook)Entity Class: package ejbframe.entity; import javax.persistence.*; @Entity @IdClass(UserPK.class) @Table(name = "users") public class User { private int userId; private String name; private String password; @Id @GeneratedValue(strategy = GenerationType.TABLE) public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
 PK class:package ejbframe.entity; import java.io.Serializable; public class UserPK implements Serializable { private int userId; public UserPK () {} public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } }
 no ids are generated, no tables for id generation created.
 If i comment out the @IdClass it works perfectly.
 help please :(
 
     
     
    