多对一双向关联
重要属性 inverse=true
作用:
强制在多的那端维护关联,避免在一的一端对集合操作出现问题,因为操纵集合维护关系有很多注意事项,一不留神就会出现问题!
设置inverse=true后,对集合进行操作,不会对关联进行设置
比如,对一端的内容进行修改,不管怎么改,关联关系仍然存在,因为强制由多端去维护!
inverse=true,不影响查询(从一端获取集合中的对象完全没问题)
inverse=true,如果通过一端的集合来保存对方,虽然对象都能够映射到数据库中,但是会造成关联的丢失,因为一端不维护关联。
多对一双向关联
1.配置文件的正确配置(双方的关联字段必须一致!都是gid)
ContactPerson类的配置文件
<hibernate-mapping
package="org.hibernate.auction">
<!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)-->
<class name="org.leadfar.hibernate.model.ContactPerson" table="t_person" >
<!-- id为数据库标识,作为主键 -->
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="group" column="gid"> </many-to-one>
</class>
</hibernate-mapping>
Group类的配置文件
<hibernate-mapping
package="org.hibernate.auction">
<!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)-->
<class name="org.leadfar.hibernate.model.Group" table="t_group" >
<!-- id为数据库标识,作为主键 -->
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="persons" lazy="true">
<key column="gid"></key>
<!-- class说明多的一方为:org.leadfar.hibernate.model.ContactPerson -->
<one-to-many class="org.leadfar.hibernate.model.ContactPerson"></one-to-many>
</set>
</class>
</hibernate-mapping>
2.可以从任意一方获取到对方的信息
3.集合类型维护关联关系时,使用业务主键复写hashcode和equals(组合关系时才在一的一端维护关联)
4.多数情况下强制约定在多的一方维护关联关系,而不在一的那方维护关系(防止更新一的一方时,多的那方的外键丢失)!!!
5.inverse=true 强制在多的一端维护关联
实体类
package org.leadfar.hibernate.model;
public class ContactPerson {
private int id;
private String name;
//一端的引用/关联的名称
private Group group;
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ContactPerson other = (ContactPerson) obj;
if (id != other.id)
return false;
return true;
}
public ContactPerson() {
// TODO Auto-generated constructor stub
}
public ContactPerson(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.hibernate.auction"> <!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)--> <class name="org.leadfar.hibernate.model.Group" table="t_group" > <!-- id为数据库标识,作为主键 --> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- inverse 默认为false . inverse=true 强制在多的一端维护两者间的关联 inverse只能用在一对多双向关联中使用 lazy控制hibernate查询语句的发出 inverse=true,hibernate对集合不进行管理,这时就强制开发人员从多的一端取维护关系了! 因为双方使用的都是gid字段,所以多的一端建立好关联后,一的一端也能通过gid来获取关联记录 --> <set name="persons" lazy="extra" inverse="true"> <key column="gid"></key> <!--双方需保持字段名一致column="gid"--> <!-- class说明多的一方为:org.leadfar.hibernate.model.ContactPerson --> <one-to-many class="org.leadfar.hibernate.model.ContactPerson"></one-to-many> </set> </class> </hibernate-mapping>
package org.leadfar.hibernate.model;
public class ContactPerson {
private int id;
private String name;
//一端的引用/关联的名称
private Group group;
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ContactPerson other = (ContactPerson) obj;
if (id != other.id)
return false;
return true;
}
public ContactPerson() {
// TODO Auto-generated constructor stub
}
public ContactPerson(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.hibernate.auction"> <!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)--> <class name="org.leadfar.hibernate.model.ContactPerson" table="t_person" > <!-- id为数据库标识,作为主键 --> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!--双方需保持字段名一致column="gid"--> <many-to-one name="group" column="gid"> </many-to-one> </class> </hibernate-mapping>
测试
package org.leadfar.hibernate.model;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test_one2Many_01_bidirection extends TestCase {
//双向关联保存对象的第一种方式:
//一的一方使用集合保存关联关系
//(操纵集合来维护关系比较麻烦,除非组合关系时才使用)
//所以,一般都是在多的一方维护关系!
public void test_save01() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session session = sfactory.openSession();
try {
session.beginTransaction();
ContactPerson cp1 = new ContactPerson("张学友");
session.save(cp1);
ContactPerson cp2 = new ContactPerson("郑伊健");
session.save(cp2);
ContactPerson cp3 = new ContactPerson("郭富城");
session.save(cp3);
Group g1 = new Group("朋友");
g1.addPerson(cp1);//将多的那方的对象存入集合
g1.addPerson(cp2);//将多的那方的对象存入集合
session.save(g1);
Group g2 = new Group("商务");
session.save(g2);
Group g3 = new Group("陌生人");
g3.addPerson(cp3);//将多的那方的对象存入集合
session.save(g3);
session.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
}
//双向关联保存对象的第二种方式:
//多的一方保存关联关系
//从多的一方维护双方关系比较方便,比操纵集合更不容易出错
//推荐从多的一方来建立并维护关系,除非组合关系出现时才在一的一方维护关系~
public void test_save02() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session session = sfactory.openSession();
try {
session.beginTransaction();
Group g1 = new Group("朋友");
session.save(g1);
Group g2 = new Group("商务");
session.save(g2);
Group g3 = new Group("陌生人");
session.save(g3);
ContactPerson cp1 = new ContactPerson("张学友");
cp1.setGroup(g1);
session.save(cp1);
ContactPerson cp2 = new ContactPerson("郑伊健");
cp2.setGroup(g2);
session.save(cp2);
ContactPerson cp3 = new ContactPerson("郭富城");
cp3.setGroup(g3);
session.save(cp3);
session.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
}
public void test_load01() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session session = sfactory.openSession();
try {
session.beginTransaction();
//双方都建立了与对方的关联
//从Group---获取ContactPerson
Group g = (Group) session.load(Group.class, 1);
Set<ContactPerson> persons = g.getPersons();
Iterator<ContactPerson> it = persons.iterator();
while(it.hasNext()) {
ContactPerson p = it.next();
System.out.println(p.getId()+","+p.getName());
}
session.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
}
public void test_load02() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session session = sfactory.openSession();
try {
session.beginTransaction();
//双方都建立了与对方的关联
//从ContactPerson---获取Group
ContactPerson cp = (ContactPerson) session.load(ContactPerson.class, 3);
Group g = cp.getGroup();
System.out.println(g.getId()+","+g.getName());
session.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
}
//多对一双向关联时,如果更新一的一方,将造成多的一方外键丢失,被置为了NULL
public void test_update01() throws Exception {
Configuration cfg = new Configuration().configure();
SessionFactory sfactory = cfg.buildSessionFactory();
Session session = sfactory.openSession();
try {
session.beginTransaction();
/*
模拟页面中传递参数过来,修改组名
struts2自动创建一个Group对象
然后更新组名---结果是,子表外键丢失,被置为了NULL
Hibernate: update t_group set name=? where id=?
Hibernate: update t_person set gid=null where gid=?
相当于清空了Group中id为1的persons集合中的内容
所以会导致Group对象与ContactPerson对象之间的关联关系丢失!
当使用了inverse=true属性时,就能避免这种现象发生
1.从一的一端添加对象到集合中,将导致无法创建外键---强制从多的一端取建立连接
2.从多的一端建立连接,就能保证更新group时,不发生外键丢失!
3.所以,在多对一双向关联时,使用inverse=true,可以防止很多麻烦事情的发生!
*/
Group g = new Group("新的Group");
g.setId(1);
session.update(g);
session.getTransaction().commit();
} catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
}
}