Я не думаю, что есть встроенная поддержка для создания пользовательских идентификаторов с помощью пользовательских аннотаций с использованием чистого API JPA-2. Но если вы хотите использовать специфичный для провайдера API, то задача довольно проста. Пример примера
Чтобы быть независимым от провайдера, попробуйте любой из следующих приемов ....
IdGeneratorHolder
public abstract class IdGeneratorHolder {
/* PersistentEntity is a marker interface */
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
/* sample impelementation */
if(Product.class.isAssignableFrom(entityType)) {
return new ProductIdGenerator();
}
return null;
}
}
Общий интерфейс IdGenerator
public interface IdGenerator {
String generate();
}
Конкретный IdGenerator - Генератор идентификатора продукта
public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}
Теперь установите сгенерированный идентификатор либо в конструкторе без аргументов ИЛИ в методе @PrePersist .
Product.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
В приведенном выше примере все идентификаторы имеют одинаковый тип, т.е. java.lang.String
. Если постоянные сущности имеют идентификаторы разных типов .....
IdGenerator.java
public interface IdGenerator {
CustomId generate();
}
CustomId.java
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
Item.java
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
Вы также можете использовать свои собственные аннотации ...
CustomIdGenerator.java
public @interface CustomIdGenerator {
IdStrategy strategy();
}
IdStrategy.java
enum IdStrategy {
uuid, humanReadable,
}
IdGeneratorHolder.java
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
Еще одна вещь .... Если мы устанавливаем id в методе @PrePersist, метод equals () не может полагаться на поле id (т.е. суррогатный ключ), мы должны использовать бизнес / натуральный ключ для реализации метода equals (). Но если мы установим в поле id какое-то уникальное значение (uuid или «app-uid», уникальное в приложении) в конструкторе без аргументов, это поможет нам реализовать метод equals ().
public boolean equals(Object obj) {
if(obj instanceof Product) {
Product that = (Product) obj;
return this.id ==that.id;
}
return false;
}
Если мы или кто-то еще вызываем (намеренно или по ошибке) аннотированный метод @PrePersist более одного раза, «уникальный идентификатор будет изменен !!!» Поэтому установка id в конструкторе без аргументов предпочтительнее. ИЛИ для решения этой проблемы установите ненулевую проверку ...
@PrePersist
public void generateId() {
if(id != null)
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
UPDATE
Если мы поместим генерацию идентификатора в
не аргументный конструктор, не так ли
вызвать проблемы при загрузке объектов
из базы данных? потому что спящий
вызовет конструктор без аргументов
в результате чего существующие идентификаторы будут
перегенерированы
Да, вы правы, я пропустил эту часть. :( На самом деле, я хотел сказать вам, что: - в моем приложении каждый объект Entity связан с Entity Entity; поэтому я создал абстрактный суперкласс с двумя конструкторами, и каждый Entity (кроме Organization) расширяет этот класс.
protected PersistentEntityImpl() {
}
protected PersistentEntityImpl(Organization organization) {
String entityId = UUIDGenerator.generate();
String organizationId = organization.getEntityId();
identifier = new EntityIdentifier(entityId, organizationId);
}
Конструктор no-arg предназначен для провайдера JPA, мы никогда не вызываем конструктор no-arg, а конструктор на основе другой организации. Как вы видете. идентификатор назначается в конструкторе на основе организации. (Я действительно упустил этот момент при написании ответа, извините за это.)
Посмотрите, сможете ли вы реализовать эту или подобную стратегию в своем приложении.
Второй вариант использовал
Аннотация @PrePersist. Я положил это в
и метод никогда не получил удар и дал
мне исключение, заявив, что мне нужно
установить идентификатор вручную. Есть
что-то еще, что я должен делать?
В идеале провайдер JPA должен вызывать методы @PrePersist (один объявлен в классе, а также все другие методы, объявленные в суперклассах) перед сохранением объекта сущности. Не могу сказать вам, что не так, если вы не покажете код и консоль.