2010-07-20 34 views
2

J'essaie d'utiliser les métadonnées JPA2 pour déterminer l'ordre d'insertion/suppression de lignes d'une base de données afin que les contraintes ne soient pas un problème (à utiliser plus tard dans le code Java). Cela fait partie d'une approche de sauvegarde/restauration utilisant JPA.JPA 2 Supprimer/Insérer un ordre depuis Metamodel

Voilà mon approche:

  1. tables groupe par nombre de relations/contraintes (une seule à plusieurs et un à un sont considérés)
  2. Tables avec zéro cas (selon # 1) peuvent avoir des enregistrements ajoutés/supprimés sans problème
  3. tables avec une instance peut avoir des enregistrements ajoutés/supprimés sans problème tant que la table liée est déjà « prêt »

Prêt par prêt Je veux dire que tous ses enregistrements de tables connexes sont remplis de sorte que les clés étrangères sont valides pour insertion ou qu'il n'y a pas d'autres tables faisant référence aux enregistrements dans cette table.

Je suis sûr que ce sera une sorte d'approche récursive mais je suis resté bloqué. Toute aide est plus que bienvenue.

Voici le code à ce jour:

/** 
* Get the execution order from the EntityManager meta data model. 
* 
* This will fail if the EntityManager is not JP2 compliant 
* @param em EntityManager to get the metadata from 
* @return ArrayList containing the order to process tables 
*/ 
protected static ArrayList<String> getProcessingOrder(EntityManager em) { 
    ArrayList<String> tables = new ArrayList<String>(); 
    //This holds the amount of relationships and the tables with that same amount 
    HashMap<Integer, ArrayList<String>> tableStats = new HashMap<Integer, ArrayList<String>>(); 
    //This holds the table and the tables referenced by it 
    HashMap<String, ArrayList<String>> references = new HashMap<String, ArrayList<String>>(); 
    for (EntityType et : em.getMetamodel().getEntities()) { 
     Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, et.getName()); 
     int amount = 0; 
     Iterator<SingularAttribute> sIterator = et.getSingularAttributes().iterator(); 
     while (sIterator.hasNext()) { 
      SingularAttribute next = sIterator.next(); 
      switch (next.getPersistentAttributeType()) { 
       case BASIC: 
       case ELEMENT_COLLECTION: 
       case EMBEDDED: 
       case ONE_TO_MANY: 
       case ONE_TO_ONE: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, 
          "Ignoring: {0}", next.getName()); 
        break; 
       case MANY_TO_MANY: 
       case MANY_TO_ONE: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, 
          "{3} has a {2} relationship: {0} with: {1}", 
          new Object[]{next.getName(), next.getBindableJavaType(), 
           next.getPersistentAttributeType().name(), et.getName()}); 
        if (!references.containsKey(et.getName())) { 
         references.put(et.getName(), new ArrayList<String>()); 
        } 
        references.get(et.getName()).add(next.getBindableJavaType().getSimpleName()); 
        amount++; 
        break; 
       default: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.SEVERE, 
          "Unexpected value: {0}", next.getName()); 
        break; 
      } 
     } 
     Iterator<PluralAttribute> pIterator = et.getPluralAttributes().iterator(); 
     while (pIterator.hasNext()) { 
      PluralAttribute next = pIterator.next(); 
      switch (next.getPersistentAttributeType()) { 
       case BASIC: 
       case ELEMENT_COLLECTION: 
       case EMBEDDED: 
       case ONE_TO_MANY: 
       case MANY_TO_MANY: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, 
          "Ignoring: {0}", next.getName()); 
        break; 
       case MANY_TO_ONE: 
       case ONE_TO_ONE: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, 
          "{3} has a {2} relationship: {0} with: {1}", 
          new Object[]{next.getName(), next.getBindableJavaType(), 
           next.getPersistentAttributeType().name(), et.getName()}); 
        if (!references.containsKey(et.getName())) { 
         references.put(et.getName(), new ArrayList<String>()); 
        } 
        references.get(et.getName()).add(next.getBindableJavaType().getSimpleName()); 
        amount++; 
        break; 
       default: 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.SEVERE, 
          "Unexpected value: {0}", next.getName()); 
        break; 
      } 
     } 
     if (!tableStats.containsKey(amount)) { 
      tableStats.put(amount, new ArrayList<String>()); 
     } 
     tableStats.get(amount).add(et.getName()); 
    } 
    Iterator<String> iterator = references.keySet().iterator(); 
    while (iterator.hasNext()) { 
     String next = iterator.next(); 
     Iterator<String> iterator1 = references.get(next).iterator(); 
     StringBuilder refs = new StringBuilder(); 
     while (iterator1.hasNext()) { 
      refs.append(iterator1.next()).append("\n"); 
     } 
     Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, "References for {0}:\n{1}", new Object[]{next, refs.toString()}); 
    } 
    //Need to sort entities with relationships even further 
    ArrayList<String> temp = new ArrayList<String>(); 
    for (Entry<Integer, ArrayList<String>> e : tableStats.entrySet()) { 
     if (e.getKey() > 0) { 
      Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, "Tables with {0} references", e.getKey()); 
      for (String t : e.getValue()) { 
       //Check the relationships of the tables 
       //Here's where I need help 
       boolean ready = true; 
       for (String ref : references.get(t)) { 
        if (!temp.contains(ref)) { 
         Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, 
           "{0} is not ready. Referenced table {1} is not ready yet", new Object[]{t, ref}); 
         ready = false; 
        } 
       } 
       if (ready) { 
        Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.INFO, "{0} is ready.", t); 
        temp.add(t); 
       } 
      } 
      //------------------------------------------------------- 
     } else { 
      temp.addAll(e.getValue()); 
     } 
    } 
    for (Entry<Integer, ArrayList<String>> e : tableStats.entrySet()) { 
     Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, 
       "Amount of relationships: {0}", e.getKey()); 
     StringBuilder list = new StringBuilder(); 
     for (String t : e.getValue()) { 
      list.append(t).append("\n"); 
     } 
     Logger.getLogger(XincoBackupManager.class.getSimpleName()).log(Level.FINER, list.toString()); 
    } 
    tables.addAll(temp); 
    return tables; 
} 

Répondre

1

je aimerais aborder ce problème avec des métadonnées de base de données JDBC.

Les méthodes suivantes de java.sql.DatabaseMetadata doivent être utilisés ici:

// to get the tables 
getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) 

// to get the reference to the table 
public ResultSet getExportedKeys(String catalog, 
           String schema, 
           String table) 
          throws SQLException 

Je l'ai utilisé cette approche dans quelques applications et il fonctionne très bien.

Bien que cette approche ne suive pas l'utilisation du méta-modèle JPA, je pense que l'utilisation du niveau de métadonnées JDBC est plus appropriée compte tenu de votre problème.

Comme il peut y avoir des dépendances cycliques qui sont difficiles à manipuler par un tel graphe de dépendance clé étrangère, vous pourriez aussi

pour suppression

  • contraintes désactiver
  • contenu suppression
  • activer les contraintes

pour ajouter

  • contraintes désactiver
  • ajouter du contenu
  • permettent contraintes
+0

Je n'ai pas problèmes pour trouver des tables et ses références de JPA2, la question est de savoir comment déterminer programatically l'ordre de suppression/ajout d'enregistrements sur la base de cette information. – javydreamercsw

+0

Cela devrait être le même problème même si j'utilise votre approche. – javydreamercsw

+0

Ok, j'ai mis à jour ma réponse. Compte tenu de la possibilité de dépendances cycliques, la désactivation des contraintes devrait être l'approche la plus simple. –