JPA – 实体设计问题
我正在开发Java桌面应用程序并使用JPA进行持久化。 我有一个问题如下:
我有两个实体:
- 国家
- 市
国家/地区具有以下属性:
- 国名(PK)
City具有以下属性:
- 城市名
现在由于两个不同国家/地区可能有两个同名的城市,因此数据库中City表的primaryKey是由CityName
和CountryName
组成的复合主键。
现在我的问题是如何将
City
的主键实现为Java中的Entity
@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
并且在上面的代码中显示这种关系,我在City
类中添加了一个country
变量。
但是,我们将重复数据( countryName
)存储在City
类对象的两个位置:一个位于country
对象中,另一个位于cityPK
对象中。
但另一方面,两者都是必要的:
-
countryName
对象中的cityPK
是必需的,因为我们以这种方式实现复合主键。 -
country
对象中的countryName
是必需的,因为它是显示对象之间关系的标准方式。
如何解决这个问题?
countryName
中的CityPK
应使用@Column(insertable = false, updatable = false)
countryName
@Column(insertable = false, updatable = false)
标记为只读@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; }
IMO处理此类问题的正确方法是使用生成的内部(通常为Long
)ID而不是自然主键 – 这消除了整个问题。 当然,这需要修改您的数据库架构,但是从您的post我认为这是可能的。
@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 }