一对多、多对一、多对多关系
一对多、多对一
在表中表达:外键
在对象中的表达:集合(使用Set集合)
在orm元数据文件中配置:
在上述实体中添加了相应的集合(Set<LinkMan>)跟对象(Customer)属性后,就得在orm元数据中去配置这两个属性了
在一的一方配置(即拥有集合的一方)
在Customer.hbm.xml中写入
<!-- name: 填写集合属性名 column: 外键名(数据库表中的外键名) class: 与我关联的类的名称,即多的一方的实体类名 --> <set name="linkman"> <!-- 要指定的外键列名 --> <key column="lkm_cust_id"></key> <!-- 指定对应的关系:一对多 --> <one-to-many class="LinkMan" /> </set>
在多的一方配置
在LinkMan.hbm.xml中写入
<!-- name: 属性名 column: 外键列名 class: 与我关联的类的名称,即一的一方的实体类的名称 --> <many-to-one name="customer" column="lkm_cust_id" class="Customer"> </many_to_one>
一对多关系操作
创建客户跟联系人,并指定客户对应的联系人
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 创建客户跟联系人 Customer customer = new Customer(); customer.setCust_name("Sacrtlett"); // 创建客户 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("Eric Jin"); LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("taylor"); // 添加关系 customer.getLinkMens().add(linkMan); customer.getLinkMens().add(linkMan1); linkMan.setCustomer(customer); linkMan1.setCustomer(customer); // 保存 session.save(customer); session.save(linkMan); session.save(linkMan1); // ------------------------------------- // 提交事务 tx.commit(); }
为客户添加联系人
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 获取要操作的客户 Customer c = session.get(Customer.class, 1L); // 创建联系人 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("mike"); // 将联系人添加到客户,将客户设置到联系人中 c.getLinkMens().add(linkMan); linkMan.setCustomer(c); // 保存 session.save(linkMan); // ------------------------------------- // 提交事务 tx.commit(); }
解除客户与联系人的关系
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 获取要操作的客户 Customer c = session.get(Customer.class, 1L); // 获取要移除的联系人 LinkMan lm = session.get(LinkMan.class, 1L); // 将联系人从客户集合集合中删除 c.getLinkMens().remove(lm); lm.setCustomer(null); // ------------------------------------- // 提交事务 tx.commit(); }
多对多
在表中表达
上面的图片中,通过第三方的一张表将Author表跟Book表联系了起来,而这第三方表最少应该有两列,一列是与Author表的id关联的外键,一列是与Book表关联的外键。
在上图中,第三张表的Author_id的跟Book_id中1对应了1,1还对应了2,这表示大灰狼参与编写了java编程跟python精通这两本书。而3也与1对应了,这表示参与了编写java精通的还有大老虎,
一个作者可以编写多本书,而一本书也可以由多个作者编写,这很好的体现了多对多的思想
在对象中表达
在orm元数据文件中配置:
由于都是多的一方,所以两方的配置应该是一模一样的,只是需要把相应的参数修改一下就可以了
在Author.hbm.xml中写入
<!-- name: 实体勒种集合的属性名 tables: 配置第三张表的表名 key下面的column: 外键名,第三张表与我关联的外键名 class: 与我关联的类名,即另外一方的实体类的类名 many-to-many: 我引用别人的外键,即第三张表与另外一方关联的外键名 --> <set name="book" tables="sys_author_book"> <!-- 要指定的外键名 --> <key column="author_id"></key> <!-- 指定对应关系 --> <many-to-many class="Book" column="book_id" /> </set>
在Book.hbm.xml中写入
由于都是多的一方,所以只需要把相应的参数做一下修改即可
<set name="author" tables="sys_author_book"> <!-- 要指定的外键名 --> <key column="book_id"></key> <!-- 指定对应关系 --> <many-to-many class="Author" column="author_id" /> </set>
多对多关系操作
添加关联
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 创建两个Author Author a1 = new Author(); a1.setAuthor_name("大灰狼"); Author a2 = new Author(); a2.setAuthor_name("大熊猫"); // 创建两个Book Book b1 = new Book(); b1.setBook_name("java编程"); Book b2 = new Book(); b2.setBook_name("python精通"); // 作者关系表达 a1.getBook().add(b1); a1.getBook().add(b2); a2.getBook().add(b1); // 书籍关系表达 /* 在这里应该注意,在上面a1跟a2已经对第三方表进行了维护,已经往第三张表里面 插入数据了,如果b1跟b2再去维护,在往是第三张表里面插入数据就会出错,所以 不需要再让书籍去维护,硬是要维护也行,只需要去书籍的orm配置文件中将inverse 配置成true放弃维护就可以了 */ // 保存 session.save(a1); session.save(a2); session.save(b1); session.save(b2); // ------------------------------------- // 提交事务 tx.commit(); }
结论:将来在开发中,如果遇到多对多关系,一定要选择一方放弃维护选择放弃谁要根据业务需求来定,比如要给作者指定书籍,那么就给作者维护。如果要为书籍配备作者,就是指定书籍维护
为作者添加书籍
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 获取Author Author a = session.get(Author.class, 1L); // 创建书籍 Book b = new Book(); b.setBook_name("c语言入门"); // 将书籍与作者关联 a.getBook().add(b); // 保存 session.save(b); // ------------------------------------- // 提交事务 tx.commit(); }
解除某个作者的一本书籍
public void test(){ // 获取session Session session = HBUtils.CurrentSession(); // 获取事务并开启 Transaction tx = session.beginTransaction(); // ------------------------------------- // 获取Author Author a = session.get(Author.class, 1L); // 获取书籍 Book b = session.get(Book.class, 1L); // 将书籍从角色中移除 a.getBook().remove(b); // ------------------------------------- // 提交事务 tx.commit(); }
配置级联跟是否维护
级联操作:cascade
有的时候觉得像 ssession.save(b) session.save(a) 既要将Author的对象持久化又要将Book对象持久化太麻烦了,于是想在持久化作者的时候顺便把书籍也持久化,这时就可以使用cascade级联操作
级联参数
save-update: 级联保存更新
delete: 级联删除
all: 相当于 save-update + delete
一对多中使用级联
在主表设置:
<set name="linkMens" cascade="save-update"> <!-- 要指定的外键列名 --> <key column="lkm_cust_id"></key> <!-- 指定对应关系 --> <one-to-many clss="linkMan" /> </set>
也可以在从表设置:
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="all"></many-to-one>
在设置之后就可以在session.save(a)的时候也session.save(b)了
注意: 一般不建议设置cascade的属性为delete,太危险!
多对多中使用级联
<set name="author" tables="sys_author_book" cascade="all"> <!-- 要指定的外键名 --> <key column="book_id"></key> <!-- 指定对应关系 --> <many-to-many class="Author" column="author_id" /> </set>
注意:在多对多中一般不建议使用级联
配置关系是否维护
在操作一对多或者多对多的时候,两方都会对外键进行维护,这显得很多余,降低效率,甚至在多对多中都去维护还会报错!只需要由一方维护就可以了,这时可以通过设置inverse来让一方放弃维护而全权交由对方去维护
inverse属性:
true:当前配置的对象不维护关系,全权交由另一方维护
false(默认):当前配置的对象自己维护关系
一对多
<!-- 设置用户对象不维护,交由联系人对象维护 --> <set name="linkMens" inverse="true"> <!-- 要指定的外键列名 --> <key column="lkm_cust_id"></key> <!-- 指定对应关系 --> <one-to-many clss="linkMan" /> </set>
当设置了不再维护后,那么客户维护联系人的代码可以省略
// c.getLinkMans().add(lm1);
// c.getLinkMans().add(lm2);
注意:只能是一的一方放弃维护,多的一方含有外键,不能自己放弃自己
如果放弃了维护,那么在一的一方在删除数据时,由于没有维护,会不允许删除,因为已经被联系人关联了,这时必须使一的一方也维护
多对多
多对多不管哪一方都能放弃维护,至于具体是哪一方放弃维护,要根据项目的实际情况来定
<!-- Book放弃维护,交给Author去维护 --> <set name="author" tables="sys_author_book" inverse="true"> <!-- 要指定的外键名 --> <key column="book_id"></key> <!-- 指定对应关系 --> <many-to-many class="Author" column="author_id" /> </set>