I am developing a Java Desktop Application and using JPA for persistence. I have a problem mentioned below:
I have two entities:
Country has the following attribute:
City has the following attribute:
Now as there can be two cities with same name in two different countries, the primaryKey for City table in the datbase is a composite primary key composed of CityName
and CountryName
.
Now my question is How to implement the primary key of the
City
as anEntity
in 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;
}
Now as we know that the relationship from Country
to City
is OneToMany
and to show this relationship in the above code, I have added a country
variable in City
class.
But then we have duplicate data(countryName
) stored in two places in the City
class' object: one in the country
object and other in the cityPK
object.
But on the other hand, both are necessary:
countryName
in cityPK
object is necessary because we implement composite primary keys in this way.
countryName
in country
object is necessary because it is the standard way of showing relashionship between objects.
How to get around this problem?
countryName
in CityPK
should be marked read-only using @Column(insertable = false, updatable = false)
and both countryName
s should be mapped to the same column (using name
property):
@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 the proper way to deal with such issues would be to use a generated internal (typically Long
) ID instead of a natural primary key - this eliminates the whole problem. Of course, this requires a modification of your DB schema, but from your post I assume that this is possible.
@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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With