2010-04-01 18 views
7

Estoy desarrollando una aplicación de escritorio Java y utilizando JPA para la persistencia. Tengo un problema mencionado a continuación:JPA - Problema de diseño de entidad

Tengo dos entidades:

  • País
  • Ciudad

país tiene el atributo siguiente:

  • CountryName (PK)

City tiene el atributo siguiente:

  • CityName

Ahora bien, como no puede haber dos ciudades con el mismo nombre en dos países diferentes, la primaryKey para la mesa de la ciudad en el datbase es una clave principal compuesta formada de CityName y CountryName.

Ahora mi pregunta es ¿Cómo poner en práctica la clave principal de la City como 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; 
    } 

Ahora que sabemos que la relación desde Country a City es OneToMany y para mostrar esta relación en el código anterior, he agregado una variable country en la clase City.

Pero entonces tenemos datos duplicados (countryName) almacenados en dos lugares en el objeto City clase: uno en el objeto country y otra en el objeto cityPK.

Pero, por otro lado, ambos son necesarios:

  • countryName en cityPK objeto es necesario porque ponemos en práctica las claves primarias compuestas de esta manera.

  • countryName en country objeto es necesario porque es la forma estándar de mostrar la relación entre los objetos.

¿Cómo evitar este problema?

Respuesta

7

countryName en CityPK están marcados como de sólo lectura utilizando @Column(insertable = false, updatable = false) y ambos countryName s debe correlacionarse con la misma columna (usando name propiedad):

@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

¿Es esta una forma estándar de tratar este tipo de problema? ¿Este problema es común en JPA? –

+0

@Yatendra: Sí, es una forma estándar (si no usas claves sustitutivas, como sugiere Peter). – axtavt

3

OMI la forma correcta de abordar estas cuestiones sería utilizar un ID interno generado (normalmente Long) en lugar de una clave primaria natural; esto elimina todo el problema. Por supuesto, esto requiere una modificación de su esquema de base de datos, pero desde su publicación asumo que esto es posible.

@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

Entonces, creo que no puedo usar 'id' en el método equals para la igualdad. ¿Correcto? –

+0

@Yatendra ¿Por qué no? Dos ciudades con el mismo nombre pero diferente país deben tener ID diferentes. Solo debe asegurarse de no insertar la misma ciudad del mismo país dos veces en la tabla. Esto podría ser impuesto por un disparador de DB o por un interceptor de Hibernate. –

+0

No puede usar 'id' en' equals() 'porque' id' es generado por la base de datos. Y no estará disponible hasta que el objeto persista. Consulte "Persistencia de Java con Hibernate" de Gavin King, consulte la discusión sobre Clave comercial y clave sustituta. – Ram

Cuestiones relacionadas