双向N-N关联
双向N-N关联需要两端都使用Set集合属性,两端都增加对集合属性的访问;双向N-N关联没有太多选择,只能采用连接表来建立两个实体之间的关联关系;
双向N-N关联需要在两端分别使用@ManyToMany修饰Set集合属性,并在两端都使用@JoinTable显示映射连接表,在两端映射连接表时,两端指定的连接表的表名应该相同,而且两端使用@JoinTable时指定的外键列的列名也应是相互对应的;
需要说明的是,如果程序希望某一端放弃控制关联关系,则可以在这一端的@ManyToMany注解中指定mappedBy属性,这一端也就无需也不能使用@JoinTable映射连接表了;
下面的例子让Person实体类与Address实体类保留双向的N-N关联关系,而且双方都能控制关联关系,因此程序需要在两边分别使用@ManyToMany,@JoinTable映射连接表;
Person实体类:
package com.anlw.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name = "person_inf")
public class Person {
// 标识属性
@Id
@Column(name = "person_id12")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private int age;
// 定义该Person实体所有关联的Address实体
@ManyToMany(targetEntity = Address.class)
// 应映射连接表,指定连接表为p_a
@JoinTable(name = "p_a",
// 映射连接表中名为person_id的外键列
// 该列参照当前实体对应数据表的person_id主键列
joinColumns = @JoinColumn(name = "person_id", referencedColumnName = "person_id12"),
// 指定连接表中address_id列参照当前实体的关联实体对应数据表的address_id主键列
inverseJoinColumns = @JoinColumn(name = "address_id", referencedColumnName = "address_id"))
private Set<Address> addresses = new HashSet<Address>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Set<Address> getAddresses() {
return addresses;
}
public void setAddresses(Set<Address> addresses) {
this.addresses = addresses;
}
}
上面程序中的注解代码映射了底层连接表的表名为p_a,并指定该连接表中包含两列:person_id,address_id,其中person_id参照person_inf表的person_id12主键列,address_id参照address_inf表的address_id主键列,由于此处管理的是N-N关联,因此不能为任何@JoinColumn注解增加unique=true;
接下来管理Address实体类时,应该让Address一端管理的连接表的表名也为p_a,且连接表中两列的列名分别为addrss_id和person_id;
Address实体类:
package com.anlw.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name = "address_inf")
public class Address {
// 标识属性
@Id
@Column(name = "address_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int addressId;
// 定义地址详细的成员变量
private String addressDetail;
// 定义该Address实体关联的Person实体
@ManyToMany(targetEntity = Person.class)
// 应映射连接表,指定连接表为p_a
@JoinTable(name = "p_a",
// 映射连接表中名为address_id的外键列
// 该列参照当前实体对应数据表的address_id主键列
joinColumns = @JoinColumn(name = "address_id", referencedColumnName = "address_id"),
// 指定连接表中person_id列参照当前实体的关联实体对应数据表的person_id主键列
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "person_id"))
private Set<Person> person = new HashSet<Person>();
public Address() {
}
public Address(String addressDetail) {
this.addressDetail = addressDetail;
}
public int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}
public String getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(String addressDetail) {
this.addressDetail = addressDetail;
}
public Set<Person> getPerson() {
return person;
}
public void setPerson(Set<Person> person) {
this.person = person;
}
}
如果程序需要让双向N-N关联的两端都能控制关联关系,那么关联关系的两端都要增加@JoinTable映射连接表,而且两端映射的连接表的表明要相同,连接表中的数据列要相互对应;