2010-12-15 94 views
0

J'ai simples 3 tables:Pourquoi ne peut pas rejoindre la 3ème table en utilisant l'annotation JPA TopLink?

Users 
-id 
-name 

Addresses 
-id 
-user_id //FK 
-location 

Phone 
-id 
-number 
-address_id //FK 
  • Les utilisateurs peuvent avoir plusieurs adresses
  • Les adresses peuvent avoir beaucoup de téléphone

Ainsi, les annotations appliquées à chaque classe d'entité ressemblerait à ceci:

Utilisateurs

@OneToMany(cascade = CascadeType.ALL, mappedBy = "user") 
    private List<Addresses> addresses; 

Adresses

@ManyToOne() 
    @JoinColumn(name = "user_id") 
    private Users user; 

    @OneToMany(mappedBy = "address") 
    private List<Phone> phone; 

Téléphone

@ManyToOne() 
    @JoinColumn(name = "address_id") 
    private Addresses address; 

L'annotation ci-dessus devrait créer la relation:

users (1) ----- (n) addresses (1) ------ (n) phone 

Je créé quelques da test ta dans MySQL et a essayé de lancer un test pour voir si le résultat de la requête qui renvoie "users" inclurait une référence aux adresses et au téléphone.

J'ai essayé avec 2 table seulement en utilisant des utilisateurs et des adresses et ai obtenu le résultat ok.

Maintenant que j'ai ajouté la table "phone" qui est la 3ème table, j'obtiens l'erreur montrée ci-dessous. Est-ce vraiment une bonne façon de rejoindre 3 tables ou plus?

Code d'essai

 try { 
      //get entity manager 
      String WEB_PU = "NoJSFPU"; 
      EntityManagerFactory factory =     Persistence.createEntityManagerFactory(WEB_PU); 
      EntityManager em = factory.createEntityManager(); 

      //run query 
      List<Users> usersList = em.createQuery("SELECT u FROM Users u").getResultList(); 

      //loop to print out each result 
      for(Users item : usersList) { 
       //display user info 
       System.out.println(item.getId() + " " + item.getFirstname()); 

       List<Addresses> addrs = item.getAddresses(); 
       for(Addresses ad : addrs) { 
        //display address info 
        System.out.println("Address:::" + ad.getLocation()); 

        List<Phone> pho = ad.getPhone(); 
        for(Phone p : pho) { 
        //display phone info 
        System.out.println("phone#" + p.getNumber()); 
        } 

       }//end inner for 
      }//end outer for 
       System.out.println("=========================="); 

      } 
      catch(Exception e) { 
       System.out.println("seriously wtf: " + e.toString()); 
       System.exit(1); 
      } 

d'erreur

Exception Description: predeploy for PersistenceUnit [NoJSFPU] failed. 
Internal Exception: Exception [TOPLINK-7250] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException 
Exception Description: [class local.test.session.Addresses] uses a non-entity [class local.test.session.Phone] as target entity in the relationship attribute [private java.util.List local.test.session.Addresses.phone]. 
+2

Pssh, je Renommez vos tables 'Users' et' Addresses' en tant que 'User' et' Address'. N'utilisez pas de pluriels dans les noms de tables (ni dans les noms de classe des classes d'entités). – BalusC

+0

Salut BalusC, il est grand temps de voir! Merci pour le conseil, mais quelle est la raison d'utiliser singulier pour les noms de table? Est-ce une convention standardisée? –

Répondre

1

Je compris. A dû spécifier en utilisant l'annotation @JoinTable.

maintenant Si je lance le code de test, les données de tous les 3 tables peuvent être obtenues: D

Adresses

@ManyToOne 
@JoinTable(name = "Addresses", joinColumns = {@JoinColumn(name="user_id", 
referencedColumnName = "user_id") }) 
private Users user; 

Téléphone

@ManyToOne 
@JoinTable(name = "Phone", joinColumns = {@JoinColumn(name="address_id", 
referencedColumnName = "address_id") }) 
private Addresses address;