Je ne pouvais pas trouver un moyen de le faire en JPA donc j'ai utilisé les écouteurs d'événements Hibernate EJB3. J'ai surmonté le saveWithGeneratedId
pour utiliser la réflexion pour vérifier l'entité pour une annotation @Id
puis pour vérifier ce champ pour une valeur. Si elle a une valeur alors j'appelle saveWithRequestedId
à la place. Sinon, je le laisse générer l'Id. Cela a bien fonctionné parce que je peux toujours utiliser la séquence pour Hibernate qui est mise en place si j'ai besoin d'un Id. La réflexion pourrait ajouter des frais généraux ainsi je pourrais le changer un peu. Je pensais avoir une méthode getId()
ou getPK()
dans toutes les entités, donc je n'ai pas à chercher quel champ est le @Id
.
Avant d'utiliser la réflexion, j'ai essayé d'appeler session.getIdentifier (entity) pour vérifier, mais je recevais TransientObjectException ("L'instance n'était pas associée à cette session"). Je ne pouvais pas trouver comment faire entrer l'Entité dans la session sans l'enregistrer d'abord, donc j'ai abandonné. Voici le code d'écoute que j'ai écrit.
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);
}
}
}
j'avais alors ajouter l'auditeur à mon persistence.xml
<property name="hibernate.ejb.event.merge" value="my.package.MergeListener"/>
Comment avez-vous déjà l'ID si l'entrée n'existe pas. C'est une mauvaise idée de mettre en œuvre ce dont vous parlez. –
J'ai 2 bases de données. L'un est sur un serveur, l'autre est local sur un PC. L'idée est que je télécharge des données sur le PC pour que je puisse travailler «hors ligne». Cela implique d'amener les entités sur le PC. Lorsque vous utilisez notre logiciel sur le PC, ils peuvent créer de nouvelles entités. J'ai besoin de la séquence pour les nouveaux entites et si elle a déjà un ID je veux insérer l'entité avec cet ID. – Allan