2011-02-22 8 views
2

je définissais un générateur pour une classe JPA:Stratégie JPA ID génération

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

Il y a des cas où je l'ai déjà une carte d'identité d'une entité, mais lorsque j'insère l'entité l'ID est généré à l'aide du générateur.

Est-il possible de définir un générateur qui ne générera un ID que s'il n'existe pas? J'utilise Hibernate en tant que fournisseur JPA.

Merci

+0

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. –

+0

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

Répondre

1

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"/> 
0

ce n'est pas une bonne idée, les séquences sont utilisées pour les clés de substitution, sont sans signification dans le sens des affaires, mais vous assure, il n'y aura pas de doublons donc aucune erreur à l'insertion du temps.

+0

J'ai une raison de le faire (voir mon commentaire ci-dessus). J'ai déjà trouvé une méthode pour éviter les doublons avec PK. Je me demandais s'il est possible d'écrire un générateur qui utilisera la séquence s'il n'y a pas de PK et ne l'utilise pas s'il y a déjà un PK. – Allan

Questions connexes