Many-to-Many Bidirectional Relationship
一般來說,多對(duì)多的雙向發(fā)生在雙方都持有對(duì)方的很多引用,A可能持有很多個(gè)B,B也可能持有很多個(gè)A,并且A和B之間還要求能夠互相查詢.在現(xiàn)實(shí)中,我們可以用如下的例子來說明這種關(guān)系:
人和航班,一個(gè)人可以訂很多次航班,可以是訂了今天的,也可以訂明天的,因?yàn)樗ぷ鞣泵?同樣的,一個(gè)航班不可能只為一個(gè)人而開,也可以接受很多個(gè)人的預(yù)訂.并且這種查詢是雙向的,一個(gè)人他可以查詢他訂了多少個(gè)航班,一個(gè)航班也可以查詢它被多少人訂了,這樣才好根據(jù)訂的情況進(jìn)行安排.
先看看代碼吧.
還是老樣子,Person類的代碼
* Person.java
*
* Created on 2007-9-15, 0:11:58
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package lbf.entitybean.test1;
import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
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.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
/**
*
* @author Admin
*/
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String sex;
private int age;
private Address address;
private List<Phone> phones;
private IDCard idCard;
private Country country;
private List<Car> cars;
private List<Flight> flights;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "PersonANDFlight", joinColumns = {@JoinColumn(name = "personID")}, inverseJoinColumns = {@JoinColumn(name = "flightID")})
public List<Flight> getFlights() {
return flights;
}
public void setFlights(List<Flight> flights) {
this.flights = flights;
}
@OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "countryID")
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
@OneToOne(cascade = CascadeType.ALL)
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "personID")
public List<Phone> getPhones() {
return phones;
}
public void setPhones(List<Phone> phones) {
this.phones = phones;
}
@OneToOne(cascade = {CascadeType.ALL})
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setId(Long id) {
this.id = id;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
}
代表航班的Flight類的代碼:
* Flight.java
*
* Created on 2007-9-24, 14:35:45
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package lbf.entitybean.test1;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Temporal;
/**
*
* @author hadeslee
*/
@Entity
public class Flight implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
@Temporal(javax.persistence.TemporalType.TIME)
public Date getArriveTime() {
return arriveTime;
}
public void setArriveTime(Date arriveTime) {
this.arriveTime = arriveTime;
}
public String getFlightNumber() {
return flightNumber;
}
public void setFlightNumber(String flightNumber) {
this.flightNumber = flightNumber;
}
public String getFromCity() {
return fromCity;
}
public void setFromCity(String fromCity) {
this.fromCity = fromCity;
}
@Temporal(javax.persistence.TemporalType.TIME)
public Date getLeaveTime() {
return leaveTime;
}
public void setLeaveTime(Date leaveTime) {
this.leaveTime = leaveTime;
}
@ManyToMany(mappedBy="flights")
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
public String getToCity() {
return toCity;
}
public void setToCity(String toCity) {
this.toCity = toCity;
}
private String flightNumber;
private String fromCity,toCity;
private Date leaveTime,arriveTime;
private List<Person> persons;
public void setId(Long id) {
this.id = id;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
}
我們?cè)賮砜匆豢碝anyToMany的聲明
{
Class targetEntity( ) default void.class;
CascadeType[] cascade( ) default {};
FetchType fetch( ) default LAZY;
String mappedBy( ) default "";
}
從代碼可以看出,注釋都差不多,只不過多對(duì)多的時(shí)候,僅僅從兩張用外鍵相連是不夠的,必須生成一張用于連接的中間表.也就如下代碼所聲明的地方:
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "PersonANDFlight", joinColumns = {@JoinColumn(name = "personID")}, inverseJoinColumns = {@JoinColumn(name = "flightID")})
public List<Flight> getFlights() {
return flights;
}
我們聲明了一張用來連接的表,并且聲明了主控端的列名和反轉(zhuǎn)端的列名,其實(shí)這個(gè)聲明不是必要的,當(dāng)我們不用@JoinTable來聲明的時(shí)候,JBOSS也會(huì)為我們自動(dòng)生成一個(gè)連接用的表,表名默認(rèn)是主控端的表名加上下劃線"_"再加上反轉(zhuǎn)端的表名.
從上面的注釋我們可以看出,此關(guān)系的主控端在Person這一方,因?yàn)槲覀兛梢栽贔light那一方看到如下注釋:
@ManyToMany(mappedBy="flights")
public List<Person> getPersons() {
return persons;
}
正是因?yàn)殡p向關(guān)系的存在,也由于Person是主控端, 所以Person要取消某次預(yù)定只要remove相應(yīng)的Flight就可以了,而Flight由于是反轉(zhuǎn)端,所以雖然它也可以得到它的所有預(yù)定的人,但是它卻無法改變這種關(guān)系,即使它remove掉了某個(gè)Person,但是這種關(guān)系并不會(huì)在數(shù)據(jù)庫(kù)里面表現(xiàn)出來,因?yàn)楫吘购桨嗍遣荒茈S便取消一個(gè)人的登機(jī)資格的.
其實(shí)按我的理解來說,多對(duì)多的雙向有點(diǎn)類似于一對(duì)多的單向,只不過雙方都是一對(duì)多,我們這個(gè)例子完全可以用一對(duì)多來實(shí)現(xiàn),但是一對(duì)多實(shí)現(xiàn)的話,就會(huì)有很多重復(fù)的數(shù)據(jù)存在,因?yàn)槊總€(gè)關(guān)系都可能會(huì)有重復(fù)的元素,比如我們這個(gè)例子,如果一對(duì)多的話,每個(gè)航班都會(huì)對(duì)應(yīng)幾百人,哪怕這幾百人下次還坐你的航班,你還要重新定義一下.因?yàn)樯洗蔚膸装偃说耐怄I已經(jīng)指向你了.還要再指向另一個(gè)你,必須要重新生成幾百個(gè)元素,所以在這種情況下,多對(duì)多就可以很好的重用數(shù)據(jù)庫(kù)里面的表了,在Person和Flight表中,都不會(huì)有重復(fù)的元素存在了.并且關(guān)系也明朗了許多.