OK, After browsing / debugging the hibernate src a lot, and trying and trying,
I guess this is not possible.
So, I got down for doing it the hard (easy :) ) way. Actually it could have taken less time to implement it this way right away rather then digging into the code.
For those having problem with composite keys with auto increment fields in them, here's the solution:
1) Create an Entity for sequence manupulation
@Entity
@Table(name = "uuid")
public class UUID {
@Id
@Column(name = "ENTITY")
private String key;
@Column(name = "VALUE")
private int value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
2) Create a generator class
public class IDVenueGenerator implements IdentifierGenerator, Configurable {
static Logger logger = Logger.getLogger(IDVenueGenerator.class);
static Object initLock = new Object();
private String entityName;
/*
* (non-Javadoc)
*
* @see org.hibernate.id.IdentifierGenerator#generate(org.hibernate.engine.SessionImplementor,
* java.lang.Object)
*/
public Serializable generate(SessionImplementor sessionImplementor,
Object object) throws HibernateException {
VenueAuditable venueEntity;
if (object instanceof VenueAuditable) {
venueEntity = (VenueAuditable) object;
} else
throw new RuntimeException("Object [" + entityName
+ "] key cannot be generated by IDVenueKey generator! ");
Session session = ((Session) sessionImplementor).getSessionFactory()
.openSession();
session.beginTransaction();
try {
UUID uuid = (UUID) session.get(UUID.class, entityName,
LockMode.UPGRADE);
if (uuid == null) {
logger.info("No key for " + entityName
+ "! Attempting to create...");
uuid = initializeUUID(session);
}
uuid.setValue(uuid.getValue() + 1);
return new IDVenueKey(venueEntity.getInitialVenue(), uuid
.getValue());
} finally {
try {
if (session.getTransaction().isActive())
session.getTransaction().commit();
} catch (Exception e) {
}
}
}
/**
* Initializes a UUID for the entitiy for one time only
*
* @param session
* @return
*/
private UUID initializeUUID(Session session) {
UUID uuid = null;
synchronized (initLock) {
logger.info("Entered into synchronized section to initialize uuid");
uuid = (UUID) session.get(UUID.class, entityName, LockMode.UPGRADE);
if (uuid == null) {
logger.info("Initializing the uuid");
uuid = new UUID();
uuid.setKey(entityName);
uuid.setValue(0);
session.save(uuid);
logger.info("UUID initialized successfully. Committing... ");
session.getTransaction().commit();
logger
.info("Committed successfully. Restoring the original transaction...");
session.beginTransaction();
} else {
logger
.info("UUID has just been initialized by another thread...");
}
logger.info("Leaving the synchronized section");
}
return uuid;
} /*
* (non-Javadoc)
*
* @see org.hibernate.id.Configurable#configure(org.hibernate.type.Type,
* java.util.Properties, org.hibernate.dialect.Dialect)
*/
public void configure(Type type, Properties params, Dialect d)
throws MappingException {
entityName = params.getProperty(ENTITY_NAME);
}
}
3) Annotate your classes like this
@GenericGenerator(name = "IDVenueKey", strategy = "com.ytg.bilette.model.IDVenueGenerator"
4) Annotate your embeddedID field like this
@GeneratedValue(generator = "IDVenueKey")
@EmbeddedId
Of course, this solutions assumes you stop using the auto_increment fields.
If you have en existing schema and cannot manupulate the structure then you may modify this code to first insert a dummy record into the table in question and then read the insert id back and pass it out from the generator...
happy coding...
|