JPA - проблема проектирования объекта

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

У меня есть два объекта:

  • Страна
  • Город

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

  • CountryName (PK)

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

  • CityName

Теперь, поскольку в двух разных странах могут быть два города с одинаковым именем, таблица primaryKey для города в базе данных представляет собой составной первичный ключ, состоящий из 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 class: один в объекте Country и другие в объекте cityPK.

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

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

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

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

Ответ 1

countryName в CityPK следует пометить только для чтения с помощью @Column(insertable = false, updatable = false), и оба countryName должны быть сопоставлены с одним и тем же столбцом (с использованием свойства 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;
   }

Ответ 2

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

@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
}