No intenté esto, pero de acuerdo con la API de Hibernate, esto no debería complicarse al crear una implementación personalizada de IdentityGenerator .
Es el método de generación obtiene y el objeto para el que está generando el valor para que pueda verificar el tipo del campo de identificación y devolver el valor apropiado para su clave principal.
public class DynamicGenerator implements IdentityGenerator
public Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
if (shouldUseAutoincrementStartegy(object)) { // basing on object detect if this should be autoincrement or not, for example inspect the type of id field by using reflection - if the type is Integer use IdentityGenerator, otherwise another generator
return new IdentityGenerator().generate(seession, object)
} else { // else if (shouldUseTextKey)
String textKey = generateKey(session, object); // generate key for your object
// you can of course connect to database here and execute statements if you need:
// Connection connection = session.connection();
// PreparedStatement ps = connection.prepareStatement("SELECT nextkey from text_keys_table");
// (...)
return textKey;
}
}
}
Teniendo esto simplemente úsalo como tu estrategia de generación:
@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
@Id
@GenericGenerator(name="seq_id", strategy="my.package.DynamicGenerator")
protected T id;
}
Para Hibernate 4, debe implementar IdentifierGenerator
interfaz.
Como lo anterior se acepta para Hibernate, aún debería ser posible crearlo de una manera más genérica para cualquier proveedor "compatible con jpa". Según JPA api en GeneratedValue anotación que puede proporcionar su generador personalizado. Esto significa que puede proporcionar el nombre de su generador personalizado y debe implementar este generador para cada proveedor jpa.
Esto significaría que necesita anotar BaseEntity con la siguiente anotación
@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
@Id
@GeneratedValue(generator="my-custom-generator")
protected T id;
}
Ahora debe registrar un generador personalizado con el nombre "mi generador personalizado" para cada proveedor de jpa que desee utilizar.
Para Hibernate, esto se hace con la anotación @GenericGenerator como se muestra antes (agregando @GenericGenerator(name="my-custom-generator", strategy="my.package.DynamicGenerator"
a BaseEntity
clase en cualquiera de id
campo o BaseEntity
el nivel de la clase debería ser suficiente).
En EclipseLink veo que puedes hacer esto a través de GeneratedValue anotación y registrarla a través de SessionCustomizer:
properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
"my.custom.CustomIdGenerator");
public class CustomIdGenerator extends Sequence implements SessionCustomizer {
@Override
public Object getGeneratedValue(Accessor accessor,
AbstractSession writeSession, String seqName) {
return "Id"; // generate the id
}
@Override
public Vector getGeneratedVector(Accessor accessor,
AbstractSession writeSession, String seqName, int size) {
return null;
}
@Override
protected void onConnect() {
}
@Override
protected void onDisconnect() {
}
@Override
public boolean shouldAcquireValueAfterInsert() {
return false;
}
@Override
public boolean shouldOverrideExistingValue(String seqName,
Object existingValue) {
return ((String) existingValue).isEmpty();
}
@Override
public boolean shouldUseTransaction() {
return false;
}
@Override
public boolean shouldUsePreallocation() {
return false;
}
public void customize(Session session) throws Exception {
CustomIdGenerator sequence = new CustomIdGenerator ("my-custom-generator");
session.getLogin().addSequence(sequence);
}
}
Cada proveedor debe proporcionar una forma de registrar el generador de ID, por lo que deberá implementar y registrar una estrategia de generación personalizada para cada uno de los proveedores si desea admitirlos a todos.