hibernate02 關係操作 多對一單向雙向
一、 多對一單向關聯
*****************************************************************************************
類:
public class Classes implements Serializable {
private Long cid;
private Set<Student> students;
// set/get屬性
}
public class Student implements Serializable {
private Long sid;
// set/get屬性
}
----------------------------------------------------------------------------------------
配置文件:
Student.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.oneToMany.domain.Student">
<id name="sid" length="3">
<generator class="increment"></generator>
</id>
</class>
</hibernate-mapping>
----------------------------------------------------------------------------------------
Classes.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.oneToMany.domain.Classes">
<id name="cid" length="5" type="java.lang.Long">
<generator class="increment"></generator>
</id>
<set name="students" cascade="all" inverse="true">
<!-- key用來描述外鍵 -->
<key>
<column name="cid"></column>
</key>
<one-to-many class="cn.itcast.oneToMany.domain.Student"/>
</set>
</class>
</hibernate-mapping>
注:
set元素對應類中的set集合,通過set元素使classes表和student表建立關聯
屬性:
cascade: 級聯操作 描述對象和對象之間的關係
save-update
當保存班級的時候,對學生進行怎樣的操作:
若學生對象在數據庫中沒有對應的值,這個時候就會執行save操作
若學生對象在數據庫中有對應的值,將該持久化對象與快照進行比對,
如果一致,則什麼也不做,如果不不一致,則發出update語句
delete
all
注: 把session.save/update一個對象的操作爲顯式操作,級聯的操作爲隱式操作
當隱式操作一個對象的時候,必須在配置文件中設置cascade屬性
inverse: 維護關係(即外鍵) 描述對象與外鍵之間的關係
true 不維護關係
false 維護關係 默認值
default false
注: inverse在那個對象的配置文件,就是該對象維護另一個對象
inverse所在的映射文件classes對classes與student之間的關係是否進行維護
維護關係體現在兩點:
1、在映射文件中inverse的值必須是false/default
2、必須在客戶端代碼上建立兩者之間的關係,更新外鍵
子元素:
key是通過外鍵的形式使倆張表建立關聯,column對應外鍵的字段
one-to-many是通過類的形式讓倆個類建立關聯
*****************************************************************************************
例子:
*****************************************************************************************
public class OneToManySingleTest {
// 1. 新建一個班級
@Test
public void testSaveClasses(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setCname("傳智上海雲一期SB");
classes.setDescription("很牛SB");
session.save(classes);
transaction.commit();
session.close();
}
// 2. 新建一個學生
@Test
public void testSaveStudent(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setSname("班長");
student.setDescription("技術很牛");
session.save(student);
transaction.commit();
session.close();
}
// 3.0. 方式1: 新建一個班級的同時新建一個學生
@Test
public void testSaveClass_Student(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setCname("傳智上海雲二期");
classes.setDescription("很牛X");
Student student = new Student();
student.setSname("班長");
student.setDescription("技術很牛X");
session.save(classes);
session.save(student); // 該方式若有n個學生,則必須保存n次
transaction.commit();
session.close();
}
// 3.1. 方式2: 新建一個班級的同時新建一個學生 在保存班級的同時,級聯保存學生
@Test
public void testSaveClass_cascade_Student_save(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setCname("傳智上海雲三期");
classes.setDescription("很牛XX");
Student student = new Student();
student.setSname("班長");
student.setDescription("技術很牛XX");
// 建立classes與student之間的聯繫
Set<Student> students = new HashSet<Student>();
students.add(student);
classes.setStudents(students);
// 保存班級,同時級聯保存了學生; 該方式保存學生只須保存一個集合即可
session.save(classes);
transaction.commit();
session.close();
}
// 3.2. 方式2: 新建一個班級的同時新建一個學生 在保存班級的同時,級聯更新學生
@Test
public void testSaveClass_cascade_Student_update(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = new Classes();
classes.setCname("傳智上海雲四期");
classes.setDescription("很牛XXX");
Student student = (Student) session.get(Student.class, 1L);
student.setSname("小班長"); // 與快照進行比對,修改了,所以執行update語句
// 建立classes與student之間的聯繫
Set<Student> students = new HashSet<Student>();
students.add(student);
classes.setStudents(students);
// 保存班級,同時級聯保存了學生; 該方式保存學生只須保存一個集合即可
session.save(classes);
transaction.commit();
session.close();
}
// 3.3. 已經存在一個班級,已經存在一些學生,新建一個學生並添加到該班級中
@Test
public void testUpdateClasses_Cascade_Student_Save(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setSname("班花");
student.setDescription("稀有人物");
Classes classes = (Classes) session.get(Classes.class, 5L);
classes.getStudents().add(student);
transaction.commit();
session.close();
}
// 3.4. 已經存在一個班級,已經存在一些學生,修改該班級的學生信息
@Test
public void testUpdateClasses_Cascade_Student_Update(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 5L);
Set<Student> students = classes.getStudents(); // 班號爲5的班級的學生集合
for(Student student:students){
student.setDescription("亞歷山大");
}
transaction.commit();
session.close();
}
/**
* 4. 已經存在一個班級,新建一個學生,建立學生與班級的關係
* 通過更新班級級聯保存學生: cascade
* 建立班級和學生之間的關係: inverse
*/
@Test
public void testSaveStudent_R_1(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 1L);
Student student = new Student();
student.setSname("技術班長");
student.setDescription("大牛");
classes.getStudents().add(student);
transaction.commit();
session.close();
}
// 5. 已經存在一個學生,新建一個班級,把學生加入到該班級中
@Test
public void testSaveClassess_R(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.get(Student.class, 2L);
Classes classes = new Classes();
classes.setCname("老畢基礎加強班");
classes.setDescription("必看,殺手鐗");
Set<Student> students = new HashSet<Student>();
students.add(student);
classes.setStudents(students);
session.save(classes);
transaction.commit();
session.close();
}
/**
* 6. 把一個學生從一個班級轉移到另一個班級中
* Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
Hibernate: select classes0_.cid as cid0_0_, classes0_.cname as cname0_0_, classes0_.description as descript3_0_0_ from Classes classes0_ where classes0_.cid=?
Hibernate: select student0_.sid as sid1_0_, student0_.sname as sname1_0_, student0_.description as descript3_1_0_ from Student student0_ where student0_.sid=?
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
Hibernate: select students0_.cid as cid0_1_, students0_.sid as sid1_, students0_.sid as sid1_0_, students0_.sname as sname1_0_, students0_.description as descript3_1_0_ from Student students0_ where students0_.cid=?
Hibernate: update Student set cid=null where cid=? and sid=?
Hibernate: update Student set cid=? where sid=?
*/
@Test
public void testTransformClass(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
// 根據數據庫語句,不需要解除關係,直接該外鍵就可以 所以可以省略這倆步
// Classes classes5 = (Classes) session.get(Classes.class, 5L);
Classes classes6 = (Classes) session.get(Classes.class, 6L);
Student student = (Student) session.get(Student.class, 1L);
// classes5.getStudents().remove(student);
classes6.getStudents().add(student);
transaction.commit();
session.close();
}
// 8. 解除一個班級和一些學生的關係
@Test
public void testR_Some(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 1L);
Set<Student> students = classes.getStudents();
// 因爲要用到角標獲取元素,而set無法獲取到角標,所以須將set集合轉換成list集合
List<Student> sList = new ArrayList<Student>(students);
// 將id爲1號的班級中id爲2,3號的學生解除關係
for(int i=0; i<sList.size(); i++){
if(sList.get(i).getSid().longValue()==2||sList.get(i).getSid().longValue()==3){
sList.remove(sList.get(i));
i--; // 注: remove取出元素,需要--
}
}
// 再將list集合還原成set集合,並建立與班級的關係
students = new HashSet<Student>(sList);
classes.setStudents(students);
transaction.commit();
session.close();
}
// 9. 解除該班級和所有學生的關係
@Test
public void testRealseAll(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 1L);
// 方式1 先查詢,再清空
// Set<Student> students = classes.getStudents();
// students.clear();
// 方式2 直接將集合置爲null,效率更高
classes.setStudents(null);
transaction.commit();
session.close();
}
// 12.刪除學生
@Test
public void testDeleteStudent(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = (Student) session.get(Student.class, 3L);
session.delete(student);
transaction.commit();
session.close();
}
// 13.1.刪除班級 在刪除班級之前,解除班級與學生的關係
// 注: 此時Classes.hbm.xml配置文件中名稱爲students的set元素的inverse屬性爲默認值false 維護關係
// 所以在刪除classes的時候hibernate內部會自動解除班級與學生的關係,然後再刪除classes
// 當Classes.hbm.xml配置文件中名稱爲students的set元素的inverse屬性爲true 不維護關係時,單項關聯無法解決
@Test
public void testDeleteClasses_1(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 2L);
session.delete(classes);
transaction.commit();
session.close();
}
// 13.2. 刪除班級 刪除班級的同時刪除學生
// 注: 此時cascade爲all inverse爲true
@Test
public void testDeleteClasses_cascade(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 3L);
session.delete(classes);
transaction.commit();
session.close();
}
}
*****************************************************************************************
二 一對多的雙向關聯
*****************************************************************************************
類:
public class Classes implements Serializable {
private Long cid;
private Set<Student> students;
// set/get屬性
}
public class Student implements Serializable {
private Long sid;
private Classes classes;
// set/get屬性
}
----------------------------------------------------------------------------------------
配置文件:
Student.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.oneToMany.domain.Student">
<id name="sid" length="3">
<generator class="increment"></generator>
</id> 、
<!-- 多對一 column 外鍵 -->
<many-to-one name="classes" class="cn.itcast.oneToMany.domain.Classes" column="cid" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
注: 一對多的操作,對多的一方操作不需要維護外鍵(inverse爲true),會自動維護;不會發出update語句來維護外鍵
若對一的一方操作,需要維護外鍵(inverse爲false),要發出update維護外鍵的語句
故一對多對多的一方操作,自動維護外鍵的關係,效率高;
----------------------------------------------------------------------------------------
Classes.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.oneToMany.domain.Classes">
<id name="cid" length="5" type="java.lang.Long">
<generator class="increment"></generator>
</id>
<set name="students" cascade="all" inverse="true">
<key>
<column name="cid"></column>
</key>
<one-to-many class="cn.itcast.oneToMany.domain.Student"/>
</set>
</class>
</hibernate-mapping>
*****************************************************************************************
例:
*****************************************************************************************
public class OneToManyDoubleTest {
// 3. 新建一個班級的同時新建一個學生
@Test
public void testSaveStudent_Cascade_Classes_Save(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setSname("班祕");
student.setDescription("班長的祕書");
Classes classes = new Classes();
classes.setCname("老畢的親子班");
classes.setDescription("都是老畢的親戚");
student.setClasses(classes);
session.save(student);
transaction.commit();
session.close();
}
// 4. 已經存在一個班級,新建一個學生,建立學生與班級的關係
// 注: 一對多,從多的一端維護關係效率較高,因爲不必維護外鍵,不需發出update語句
@Test
public void testSaveStudent_R(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Student student = new Student();
student.setSname("朱有才");
student.setDescription("才華橫溢");
Classes classes = (Classes) session.get(Classes.class, 6L);
student.setClasses(classes);
session.save(student);
transaction.commit();
session.close();
}
// 8. 解除一個班級和一些學生的關係
@Test
public void testRelease_R(){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Classes classes = (Classes) session.get(Classes.class, 6L);
Student student1 = (Student) session.get(Student.class, 1L);
Student student6 = (Student) session.get(Student.class, 6L);
student1.setClasses(null);
student6.setClasses(null);
transaction.commit();
session.close();
}
}
*****************************************************************************************
三、總結
1、 如果讓一的一方維護關係,取決於的因素有:
1.在一的一方的映射文件中,set的inverse屬性爲default/false
2.在客戶端的代碼中,通過一的一方建立關係
3.session.save/update方法是用來操作表的,和操作關係無關
2、 採用級聯的方式通過保存一個對象從而保存關聯對象
1.如果session.save操作的對象是A,這個時候應該看A.hnm.xml文件,看set元素中的cascade屬性是否設置有級聯保存
2.在客戶端通過A建立關聯
3.在客戶端執行session.save(A)
3、 一對多的情況,多的一方維護關係效率比較高
1.在多的一方many-to-one中沒有inverse屬性
2.在客戶端通過多的一方建立關聯
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.