1.双向 1-n 与 双向 n-1 是完全相同的两种情形,这里使用双向多对一来演示
双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然.
出版社和图书的关系:Publishers——Books
2.实体类
n端
Books.java
public class Books {
private Integer Id;
private String Title;
private String Author;
private String ISBN;
private int WordCount;
private double UnitPrice;
private String ContentDescription;
//实体类类型属性
private Publishers publisher;
//忽略getter和setter方法
...
}
1端
Publishers.java
public class Publishers {
private Integer id;
private String Name;
//集合属性
private Set<Books> bks = new HashSet<>();
//忽略getter和setter方法
...
}
3.映射文件
n端:
<hibernate-mapping package="com.withXml.bothmanyToone.entity" auto-import="false">
<class name="Books" table="BOTH_BOOKS">
<id name="Id" type="java.lang.Integer" access="field">
<column name="ID" />
<generator class="native" />
</id>
<property name="Title" type="java.lang.String">
<column name="TITLE" />
</property>
<property name="Author" type="java.lang.String">
<column name="AUTHOR" />
</property>
<property name="ISBN" type="java.lang.String">
<column name="ISBN" />
</property>
<property name="WordCount" type="integer">
<column name="WORD_COUNT"/>
</property>
<!-- 映射数据表字段你的类型,可以在property 里面使用type设置,也可以在column里面使用 sql-type-->
<property name="UnitPrice">
<column name="UNIT_PRICE" sql-type="double" />
</property>
<property name="ContentDescription" type="java.lang.String">
<column name="CONTENT_DESCRIPTION" />
</property>
<!-- 配置多对一关联映射 -->
<many-to-one name="publisher" class="Publishers"
column="PUBLISHER_ID" cascade="save-update"></many-to-one>
</class>
</hibernate-mapping>
1端
<hibernate-mapping package="com.withXml.bothmanyToone.entity" auto-import="false">
<class name="Publishers" table="BOTH_PUBLISHERS">
<id name="id" type="java.lang.Integer" access="field">
<column name="ID" />
<generator class="native" />
</id>
<property name="Name" type="java.lang.String">
<column name="NAME" />
</property>
<!--
cascade(级联)级联的意思是指两个对象之间的操作联运关系,对一个对象执行了操作之后,
对其指定的级联对象也需要执行相同的操作,取值:all,none,save_update,delete。
1.all:代码在所有情况下都执行级联操作
2.none:在所有情况下都不执行级联操作
3.save-update:在保存和更新的情况下执行级联操作
4.delete:在删除的时候执行级联操作
inverse:属性设置为true代表一的一方不在拥有关联关系的控制权,而把控制权交给多的一方
-->
<set name="bks" lazy="false" inverse="true" cascade="save-update,delete">
<!-- <key>指定PUBLISHERS数据表的外键,使用的是BOOKS表中的PUBLISHER_ID列 -->
<key column="PUBLISHER_ID"></key>
<one-to-many class="Books"/>
</set>
</class>
</hibernate-mapping>
4.CRUD测试
①保存
/**
* 保存操作,保存1的一端
*/
@Test
public void testBothManyToOneSave(){
//创建出版社对象
Publishers publisher = new Publishers();
publisher.setName("北京大学出版社");
//新建图书对象
Books book = new Books();
book.setTitle("大学英语");
book.setISBN("2018012103");
book.setAuthor("李玲");
book.setWordCount(10000);
book.setUnitPrice(95.5);
book.setContentDescription("无");
//新建图书对象
Books book2 = new Books();
book2.setTitle("管理学");
book2.setISBN("2018012104");
book2.setAuthor("张青");
book2.setWordCount(10000);
book2.setUnitPrice(95.5);
book2.setContentDescription("无");
//双向维护关系
//设置关联关系,指定一到多的关联关系 ,若由1端维护关系,会产生update语句,影响效率,
//所以在1端映射文件中设置inverse="true",控制权交给n端维护关系
publisher.getBks().add(book);
publisher.getBks().add(book2);
//设置关联关系,指定多到一的关联关系
book.setPublisher(publisher);
book2.setPublisher(publisher);
//执行保存,设置cascade级联属性之后,
//只保存一端即可(哪一端设置级联属性,可以只保存那一段,两端都设置,则任意一端都可以执行保存)
session.save(publisher);
}
②保存2
/**
* 保存操作
*/
@Test
public void testBothManyToOneSave2(){
//创建出版社对象
Publishers publisher = new Publishers();
publisher.setName("北京大学出版社");
//新建图书对象
Books book = new Books();
book.setTitle("大学英语");
book.setISBN("2018012103");
book.setAuthor("李玲");
book.setWordCount(10000);
book.setUnitPrice(95.5);
book.setContentDescription("无");
//新建图书对象
Books book2 = new Books();
book2.setTitle("管理学");
book2.setISBN("2018012104");
book2.setAuthor("张青");
book2.setWordCount(10000);
book2.setUnitPrice(95.5);
book2.setContentDescription("无");
//双向维护关系
//设置关联关系,指定一到多的关联关系 ,因为会产生update语句,影响效率
//publisher.getBks().add(book);
//publisher.getBks().add(book2);
//设置关联关系,指定多到一的关联关系
book.setPublisher(publisher);
book2.setPublisher(publisher);
//执行保存,设置cascade级联属性之后,
//只保存一端即可(哪一端设置级联属性,可以只保存那一段,两端都设置,则任意一端都可以执行保存)
session.save(book);
session.save(book2);
}
③查询
/**
* 查询操作
* 查询某出版社出版的图书
*/
@Test
public void testBothManyToOneGet(){
Publishers publisher = (Publishers) session.get(Publishers.class, 1);
Iterator<Books> iterator = publisher.getBks().iterator();
System.out.println(publisher.getName() + "出版的图书有:");
while(iterator.hasNext()){
Books book = iterator.next();
System.out.println(book.getTitle());
}
}
④修改
/**
* 修改操作
* 把id为1的图书所对应的id为1出版社修改为id为2出版社
*/
@Test
public void testBothManyToOneUpdate(){
//获取出版社对象
Publishers publisher = (Publishers) session.get(Publishers.class, 1);
//获取图书对象
Books book = (Books) session.get(Books.class, 1);
book.setPublisher(publisher);
session.update(book);
}
⑤n端删除
/**
* 删除操作,删除图书信息
*
*/
@Test
public void testBothManyToOneDelete(){
Books book = (Books) session.get(Books.class, 12);
session.delete(book);
}
⑥1端删除
/**
* 删除操作,删除出版社信息,以及出版社出版的图书
*
*/
@Test
public void testBothManyToOneDelete2(){
Publishers publisher = (Publishers) session.get(Publishers.class, 1);
session.delete(publisher);
}
五.总结
(双向n对1):其实就是单向n对1和单向1对n同时使用
1端
①实体类:添加集合属性
②映射文件:使用<set>
元素映射集合属性,
name属性指定映射的属性名
inverse属性设置为true代表一的一方不在拥有关联关系的控制权,而把控制权交给多的一方 <key>
元素指定外键,属性值要与n端的<many-to-one>
元素的column属性值一致,
使用<one-to-many class="Books"/>
元素映射关联关系
详细如下:
<!--
cascade(级联)级联的意思是指两个对象之间的操作联运关系,对一个对象
执行了操作之后,对其指定的级联对象也需要执行相同的操作,
取值:all,none,save_update,delete。
1.all:代码在所有情况下都执行级联操作
2.none:在所有情况下都不执行级联操作
3.save-update:在保存和更新的情况下执行级联操作
4.delete:在删除的时候执行级联操作
inverse:属性设置为true代表一的一方不在拥有关联关系的控制权,
而把控制权交给多的一方
-->
<set name="bks" lazy="false" inverse="true" cascade="save-update,delete">
<!-- <key>指定外键 -->
<key column="PUBLISHER_ID" not-null="true"></key>
<one-to-many class="Books"/>
</set>
n端:
①实体类:添加一个n端实体类型的属性
②映射文件:使用<many-to-one>
元素映射实体类型的属性,column属性指定外键,class指定关联的类的名字。
详细如下:
<!-- 配置多对一关联映射 -->
<many-to-one name="publisher" class="Publishers"
column="PUBLISHER_ID" cascade="save-update">
</many-to-one>