組件
他們沒有自己的標(biāo)識(shí)符,其主鍵是它所屬實(shí)體擁有映射的數(shù)據(jù)庫標(biāo)識(shí)符,內(nèi)嵌的組件有獨(dú)立的生命周期:在保存所擁有的實(shí)體實(shí)例時(shí).也會(huì)保存該組件實(shí)例,當(dāng)其所擁有實(shí)體實(shí)例被刪除時(shí),也會(huì)刪除該組件實(shí)例,Hibernate甚至不必為此執(zhí)行任何特殊的SQL,所有數(shù)據(jù)都位于一行中.
Java沒有組合的概念,類或?qū)傩圆荒鼙粯?biāo)記為組件或組合生命周期,與實(shí)體的唯一區(qū)別是數(shù)據(jù)庫標(biāo)識(shí)符:組件類沒有獨(dú)立的標(biāo)識(shí);因此,組件類不需要標(biāo)識(shí)符屬性或標(biāo)識(shí)符映射,他是一個(gè)簡(jiǎn)單的POJO.代碼:
@Embeddable
public class Address {
@NotNull
@Column(nullable = false)
private String street;
@NotNull
@Column(nullable = false, length = 5)
private String zipcode;
@NotNull
@Column(nullable = false)
private String city;
public Address() {
}
public Address(String street, String zipcode, String city) {
this.street = street;
this.zipcode = zipcode;
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
使用方法:
@Entity
@Table(name = "t_Users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//Address是@Embeddable 這里不需要注解
private Address homeAddress;
public Long getId() {
return id;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
}
Hibernate會(huì)檢測(cè)Address類是否使用@Embeddable進(jìn)行了注解, street, zipcode,city列是在t_Users表上映射的,即所屬實(shí)體的表,
在更為現(xiàn)實(shí)的場(chǎng)景中,一個(gè)用戶可能會(huì)將不同的地址用于不同的目的,例如User有家庭地址,還有賬單地址:
重寫嵌入屬性
billingAddress是User類的另一個(gè)嵌入組件屬性,所以必須在t_Users表中保存另一個(gè)address,這就造成了映射沖突,到目前為止,架構(gòu)中只有在street,zipcode,city.中存儲(chǔ)一個(gè)address列,需要額外的列來存儲(chǔ)用于每個(gè)User行的另一個(gè)Address.映射billingAddress時(shí),要重寫列的名稱
@Entity
@Table(name = "t_Users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street",
column = @Column(name = "billing_street")),
@AttributeOverride(name = "zipcode",
column = @Column(name = "billing_zipcode", length = 5)),
@AttributeOverride(name = "city",
column = @Column(name = "billing_city"))
})
private Address billingAddress;
public Address getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(Address billingAddress) {
this.billingAddress = billingAddress;
}
public Long getId() {
return id;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
}
數(shù)據(jù)庫實(shí)體:t_Users
@AttributeOverrides會(huì)選擇地重寫嵌入類的屬性映射;在這個(gè)示例中,重寫了全部3個(gè)屬性并且提供了不同的列名,現(xiàn)在可以在t_Users表中存儲(chǔ)兩個(gè)Address實(shí)例了,每個(gè)實(shí)例位于不同的列中.
用于組件
用于組件屬性的每個(gè)@AttributeOverride都完成了:重寫的屬性上的任何JPA或Hibernate都會(huì)忽略,這意味著Address類上的@Column注解會(huì)被忽略-----所有的billing_*列都可為null,(不過 Bean驗(yàn)證依舊會(huì)識(shí)別組件屬性上的@NotNull注解;Hibernate只會(huì)重寫持久化注解).
映射嵌套的可嵌入組件
考慮一下Address類以及它如何封裝地址詳情,不使用簡(jiǎn)單的city字符串.而是將這一個(gè)詳情移動(dòng)到一個(gè)新的City可嵌入類中,代碼如下:
City類
@Embeddable
public class City {
@NotNull
@Column(nullable = false, length = 5)
private String zipcode;
@NotNull
@Column(nullable = false)
private String name;
@NotNull
@Column(nullable = false)
private String country;
public City() {
}
public City(String zipcode, String name, String country) {
this.zipcode = zipcode;
this.name = name;
this.country = country;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Address類
@Embeddable
public class Address {
@NotNull
@Column(nullable = false)
private String street;
@NotNull
@AttributeOverrides(
@AttributeOverride(name = "name",
column = @Column(name = "city", nullable = false))
)
private City city;
public Address() {
}
public Address(String street, City city) {
this.street = street;
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
}
User類
@Entity
@Table(name = "t_Users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "street",
column = @Column(name = "billing_street")),
@AttributeOverride(name = "city.zipcode",
column = @Column(name = "billing_zipcode", length = 5)),
@AttributeOverride(name = "city.name",
column = @Column(name = "billing_city")),
@AttributeOverride(name = "city.country",
column = @Column(name = "billing_country"))
})
private Address billingAddress;
public Address getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(Address billingAddress) {
this.billingAddress = billingAddress;
}
public Long getId() {
return id;
}
public Address getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
}
數(shù)據(jù)庫實(shí)體:t_Users
可以在任何級(jí)別聲明@AttributeOverrides,正如City類的name屬性所做的那樣,將它映射到City列,這可以使用(所示的)Address中的@AttributeOverride或者根實(shí)體類User中重寫來實(shí)現(xiàn),嵌套屬性可以使用.符號(hào)來引用:例如,@AttributeOverride(name = "city.country",column = @Column(name = "billing_country"))引用了Address的#City#name屬性.