Стратегия создания идентификатора JPA - PullRequest
2 голосов
/ 22 февраля 2011

Я определил генератор для класса JPA:

<sequence-generator name="MY_SEQ" allocation-size="-1"
    sequence-name="MY_SEQ"
    initial-value="100000000" />

В некоторых случаях у меня уже есть идентификатор для сущности, но когда я вставляю сущность, идентификатор генерируется с помощью генератора.

Можно ли определить генератор, который будет генерировать Id, только если он не существует?

Я использую Hibernate в качестве поставщика JPA.

Спасибо

Ответы [ 2 ]

1 голос
/ 25 февраля 2011

Я не смог найти способ сделать это в JPA, поэтому я использовал прослушиватели событий Hibernate EJB3. Я перебрал saveWithGeneratedId, чтобы использовать отражение, чтобы проверить сущность для аннотации @Id, а затем проверить это поле на предмет значения. Если оно имеет значение, я звоню saveWithRequestedId. В противном случае я позволю ему генерировать Id. Это работало хорошо, потому что я все еще могу использовать последовательность для Hibernate, которая настроена, если мне нужен Id. Отражение может добавить накладные расходы, поэтому я могу немного изменить его. Я думал о том, чтобы иметь метод getId() или getPK() во всех сущностях, поэтому мне не нужно искать, какое поле является @Id.

Прежде чем использовать отражение, я пытался вызвать session.getIdentifier (entity) для проверки, но я получал TransientObjectException («Экземпляр не был связан с этим сеансом»). Я не мог понять, как получить сущность в сеанс, не сохранив ее сначала, поэтому я сдался. Ниже приведен код слушателя, который я написал.

public class MergeListener extends org.hibernate.ejb.event.EJB3MergeEventListener
 {



    @Override
    protected Serializable saveWithGeneratedId(Object entity, String entityName, Object anything, EventSource source, boolean requiresImmediateIdAccess) {


        Integer id = null;


            Field[] declaredFields = entity.getClass().getDeclaredFields();

            for (Field field : declaredFields) {

                Id annotation = field.getAnnotation(javax.persistence.Id.class);

                if(annotation!=null) {


                    try {
                        Method method = entity.getClass().getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
                        Object invoke = method.invoke(entity);

                       id = (Integer)invoke;


                    } catch (Exception ex) {
                      //something failed (method not found..etc) , keep going anyway
                    }

                    break;

                }
            }



       if(id == null ||
                id == 0) {
        return super.saveWithGeneratedId(entity, entityName, anything, source, requiresImmediateIdAccess);
        } else {

            return super.saveWithRequestedId(entity, id, entityName, anything, source);
        }
    }
}

Затем мне пришлось добавить слушателя в мой файл persistence.xml

 <property name="hibernate.ejb.event.merge" value="my.package.MergeListener"/>
0 голосов
/ 23 февраля 2011

Это не очень хорошая идея, последовательности используются для суррогатных ключей, бессмысленны в деловом смысле, но уверяют вас, дубликатов не будет, поэтому нет ошибки при вставке времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...