2010-04-01 4 views
7

Я разрабатываю приложение Java Desktop и использую JPA для сохранения. У меня есть проблема, указанных ниже:JPA - проблема с дизайном сущности

У меня есть две сущности:

  • Страна
  • Сити

Страна имеет следующий атрибут:

  • CountryName (PK)

Город имеет следующий атрибут:

  • CITYNAME

Теперь, как там может быть два города с таким же названием в двух разных странах, PrimaryKey для городской таблицы в datbase является составным первичным ключом, состоящий от CityName и CountryName.

Теперь мой вопрос Как реализовать первичный ключ City как Entity в 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; 
    } 

Теперь, когда мы знаем, что отношения с Country к City является OneToMany и показать это в приведенном выше коде, я добавил переменную country в классе City.

Но тогда у нас есть повторяющиеся данные (countryName), хранящихся в двух местах в объекте City класса: один в country объекте и других в cityPK объекте.

Но с другой стороны, обе необходимы:

  • countryName в cityPK объект необходим, потому что мы реализуем составные первичные ключи в этом случае.

  • countryName в country объект необходим, потому что это стандартный способ отображения relashionship между объектами.

Как обойти эту проблему?

ответ

7

countryName в CityPK должен быть отмечен только для чтения с помощью @Column(insertable = false, updatable = false) и оба countryName s должны быть отображены в той же колонке (с использованием name свойства):

@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

Это стандартный способ решения этой проблемы? Является ли эта проблема распространенной в JPA? –

+0

@ Yatendra: Да, это стандартный способ (если вы не используете суррогатные ключи, как предлагает Питер). – axtavt

3

ИМО правильный способ решения таких вопросов будет использовать сгенерированный внутренний (обычно Long) идентификатор вместо натурального первичного ключа - это устраняет всю проблему. Конечно, для этого требуется модификация вашей схемы БД, но из вашего поста я предполагаю, что это возможно.

@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

Тогда я думаю, что я не могу использовать 'id' в методе equals для равенства. Верный? –

+0

@ Yatendra Почему бы и нет? В двух городах с одинаковым именем, но в разных странах должны быть разные идентификаторы. Вам нужно только убедиться, что вы не вставляете один и тот же город из одной страны дважды в таблицу. Это может быть вызвано триггером DB или перехватчиком Hibernate. –

+0

Вы не можете использовать 'id' в' equals() ', потому что' id' генерируется базой данных. И не будет доступен, пока объект не будет сохранен. Обратите внимание на «Сохранение Java с помощью Hibernate» Гэвина Кинга, см. Обсуждение бизнес-ключа и суррогатного ключа. – Ram