单向多对一关联
在关系型数据库理论中,“多对一”关联同于“一对多”关联,且为了消除数据冗余,在两个关系之间不存在“多对多”关联,“多对多”关联要通过连接表来实现。因此在关系型数据库中只有“一对一”和“一对多(多对一)”,且都是单向的。而在hibernate当中,为了保证关联双方的映射可以通过多种方式进行,“单向一对多”关联和“单向多对一”被认为是两种不同的关联,其主要区别是在于哪个表的映射文件中进行<many to one>的配置, 进行<many to one>配置的一方便是“多”。 由于“单向一对多”关联的应用比较少见并不被hibernate推荐使用,下面仅对"单向多对一"关联进行说明 (提倡此种用法,提高hibernate性能)
对于<many to one>中,主要属性说明如下
name(必需): 设定“many”方所包含的“one”方所对应的持久化类的属性名
column(可选): 设定one方的主键,即持久化类的属性对应的表的外键
class(可选): 设定one方对应的持久化类的名称,即持久化类属性的类型
not-null(可选): 如果为true,,表示需要建立相互关联的两个表之间的外键约束
cascade(可选): 级联操作选项,默认为none
单向多对一(many to one)关联是最常见的单向关联关系。假设多个人(Person)可以有一个住址(Address),我们只关心人实体找到对应的地址实体,而无须关心从某个地址找到全部用户.
下面是将Person.hbm.xml 和 Address.hbm.xml 文件合并到一个 Chapter801.hbm.xml 文件
Chapter801.hbm.xml映射文件
<hibernate-mapping>
<class
name="hibernate.wizard.chapter8.Person"
table="C8_Person"
schema="dbo"
>
<id
name="personId"
type="java.lang.String"
column="personId"
>
<generator class="assigned" />
</id>
<!-- Associations -->
<many-to-one name="Address"
column="addressId"
class="hibernate.wizard.chapter8.Address"
not-null="true"
cascade="none"
/>
</class>
<class
name="hibernate.wizard.chapter8.Address"
table="C8_Address"
schema="dbo"
>
<id
name="addressId"
type="java.lang.String"
column="addressId"
>
<generator class="assigned" />
</id>
<property
name="addressName"
type="java.lang.String"
column="addressName"
not-null="false"
length="50"
>
</property>
<!-- Associations -->
</class>
</hibernate-mapping>
持久化类
Person.hbm.xml文件定义了一个<many to one>的关联,而Address.hbm.xml文件未定义的任何关联,说明可以从Person类单向关联到Address类。由于Person类与Address类是“多对一”的关系。因此需要在Person类中声明一个Address类型的地属性address,以实现从一个Person对象导航到与之相关联的Address对象的目的。为了使Person对象与Address对象关联,还需要为Person类构造一人带有Address类型的参数的构造函数
Person类
public class Person implements Serializable {
private String personId;
private String addressId;
private Address address; //声明了Address类型的属性
public Person(String personId, String addressId) {
this.personId = personId;
this.addressId = addressId;
}
public Person(String personId,Address address){
this.personId = personId;
this.addressId=address.getAddressId();
this.address=address;
}
public Person(String personId) {
this.personId = personId;
}
public Person() {
}
public String getPersonId() {
return this.personId;
}
public void setPersonId(String personId) {
this.personId = personId;
}
public String getAddressId() {
return this.addressId;
}
public void setAddressId(String addressId) {
this.addressId = addressId;
}
public String toString() {
return new ToStringBuilder(this)
.append("personId", getPersonId())
.toString();
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address类
public class Address implements Serializable {
private String addressId;
private String addressName;
// private Set people=new HashSet(); //双向一对多关联时才用
public Address(String addressId,String addressName) {
this.addressId = addressId;
this.addressName=addressName;
}
public Address() {
}
public String getAddressId() {
return this.addressId;
}
public void setAddressId(String addressId) {
this.addressId = addressId;
}
public String toString() {
return new ToStringBuilder(this)
.append("addressId", getAddressId())
.toString();
}
public String getAddressName() {
return addressName;
}
public void setAddressName(String addressName) {
this.addressName = addressName;
}
public Set getPeople() {
return people;
}
public void setPeople(Set people) {
this.people = people;
}
}
建立单向多对一关联需要注意以下几点问题
1 .在many方的映射文件中,使用<many to one>标识进行关联映射的定义
2 .many方的持久化类中必须声明one方对应的持久化类的属性,用于实现多对一的导航,如上例中的private Address address;
3 .应用程序中必须创建 many 方到one方的关联,示例中使用带有one方对应的持久化类的参数类型的构造函数是一种方式,另外也可以直接使用many方的set方法创建关联,如pl.setAddress(addr)
4. 级联操作定义在<many to one>操作中,如果将cascade属性设为all或save-update,那么在应用程序中只需要用 Session的sava方法持久化many方的对象即可,如 session.save(p3)