Nie próbowałem tego, ale zgodnie z api Hibernate nie powinno to być skomplikowane przez tworzenie niestandardowej implementacji IdentityGenerator .
Jest to metoda generate i obiekt, dla którego generujesz wartość, dzięki czemu możesz sprawdzić typ pola id i zwrócić odpowiednią wartość dla swojego klucza podstawowego.
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;
}
}
}
Mając to, po prostu użyj go jako strategii generowania:
@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
@Id
@GenericGenerator(name="seq_id", strategy="my.package.DynamicGenerator")
protected T id;
}
W przypadku Hibernate 4 należy zaimplementować IdentifierGenerator
interfejs.
Jak powyżej jest akceptowane dla Hibernate, nadal powinno być możliwe stworzenie go w bardziej ogólny sposób dla dowolnego dostawcy "zgodnego z jpa". Według JPA api w GeneratedValue adnotację, którą możesz podać w swoim niestandardowym generatorze. Oznacza to, że możesz podać nazwę swojego niestandardowego generatora i powinieneś zaimplementować ten generator dla każdego dostawcy jpa.
Oznaczałoby to, że musisz dodać do BaseEntity następującą adnotację
@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
@Id
@GeneratedValue(generator="my-custom-generator")
protected T id;
}
Teraz musisz zarejestrować niestandardowy generator o nazwie "my-custom-generator" dla każdego dostawcy jpa, którego chcesz użyć.
W przypadku Hibernate jest to z pewnością wykonywane przez adnotację @GenericGenerator, jak pokazano wcześniej (dodając @GenericGenerator(name="my-custom-generator", strategy="my.package.DynamicGenerator"
do BaseEntity
klasa na id
pole lub BaseEntity
poziom klasy powinien być wystarczający).
W EclipseLink widzę, że możesz to zrobić za pomocą GeneratedValue adnotację i rejestrację za pomocą 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);
}
}
Każdy dostawca musi umożliwić zarejestrowanie generatora identyfikatorów, więc jeśli chcesz obsługiwać ich wszystkich, musisz wdrożyć i zarejestrować niestandardową strategię generowania dla każdego dostawcy.