JPA - проблема проектирования объекта
Я разрабатываю приложение Java Desktop и использую JPA для сохранения. У меня есть проблема, упомянутая ниже:
У меня есть два объекта:
Страна имеет следующий атрибут:
Город имеет следующий атрибут:
Теперь, поскольку в двух разных странах могут быть два города с одинаковым именем, таблица 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
}