2010-04-01 5 views
7

Je développe une application Java Desktop et utilise JPA pour la persistance. J'ai un problème mentionné ci-dessous:JPA - Problème de conception d'entité

J'ai deux entités:

  • Pays
  • Ville

Pays a l'attribut suivant:

  • CountryName (PK)

Ville a l'attribut suivant:

  • CityName

Maintenant, comme il peut y avoir deux villes avec le même nom dans deux pays différents, la primaryKey pour la table de la ville dans la datbase est une clé primaire composite composé de CityName et CountryName.

Maintenant, ma question est de savoir comment mettre en œuvre la clé primaire de la City comme Entity en Java

@Entity 
    public class Country implements Serializable { 
     private String countryName; 

     @Id 
     public String getCountryName() { 
      return this.countryName; 
     } 
    } 

    @Entity 
    public class City implements Serializable { 
      private CityPK cityPK; 
      private Country country; 

      @EmbeddedId 
      public CityPK getCityPK() { 
       return this.cityPK; 
      } 
    } 


    @Embeddable 
    public class CityPK implements Serializable { 
     public String cityName; 
     public String countryName; 
    } 

Maintenant que nous savons que la relation Country-City est OneToMany et de montrer cette relation dans le code ci-dessus, j'ai ajouté une variable country dans la classe City.

Mais nous avons des données en double (countryName) stockées dans deux endroits dans l'objet de classe City: un dans l'objet country et d'autres dans l'objet cityPK.

Mais d'autre part, les deux sont nécessaires:

  • countryName dans cityPK objet est nécessaire parce que nous mettons en œuvre les clés primaires composites de cette façon.

  • countryName dans country objet est nécessaire parce que c'est la manière standard de montrer relashionship entre les objets.

Comment contourner ce problème?

Répondre

7

countryName dans CityPK doivent être marqués en lecture seule utilisant @Column(insertable = false, updatable = false) et les deux countryName s doivent être mises en correspondance avec la même colonne (en utilisant name propriété):

@Entity 
    public class City implements Serializable { 
      @EmbeddedId 
      private CityPK cityPK; 

      @ManyToOne 
      @JoinColumn(name = "countryName") 
      private Country country; 
    } 


    @Embeddable 
    public class CityPK implements Serializable { 
     public String cityName; 

     @Column(name = "countryName", insertable = false, updatable = false) 
     public String countryName; 
    } 
+0

Est-ce une façon standard de traiter ce type de problème? Ce problème est-il courant dans JPA? –

+0

@Yatendra: Oui, c'est un moyen standard (si vous n'utilisez pas de clés de substitution, comme le suggère Peter). – axtavt

3

OMI la bonne façon de traiter ces questions serait pour utiliser un ID interne généré (généralement Long) au lieu d'une clé primaire naturelle - cela élimine tout le problème. Bien sûr, cela nécessite une modification de votre schéma de base de données, mais à partir de votre message, je suppose que c'est possible.

@Entity 
public class City implements Serializable { 
    private Long id; 

    private String name; 
    private Country country; 

    @Id 
    @GeneratedValue 
    @Column(name = "CITY_ID") 
    public Long getId() { 
     return this.id; 
    } 
    private void setId(Long id) { 
     this.id = id; 
    } 

    // more getters, setters and annotations 
} 
+0

Ensuite, je pense que je ne peux pas utiliser 'id' dans la méthode equals pour l'égalité. Correct? –

+0

@Yatendra Pourquoi pas? Deux villes avec le même nom mais un pays différent doivent avoir des ID différents. Vous devez seulement vous assurer que vous n'insérez pas deux fois la même ville du même pays dans la table. Cela pourrait être appliqué par un déclencheur DB ou par un intercepteur Hibernate. –

+0

Vous ne pouvez pas utiliser 'id' dans' equals() 'car' id' est généré par la base de données. Et ne sera pas disponible jusqu'à ce que l'objet est persisté. Reportez-vous à Java Persistence with Hibernate de Gavin King, voir la discussion sur la clé Business et la clé de substitution. – Ram