一对多、多对一、多对多关系

一对多、多对一

在表中表达:外键

在对象中的表达:集合(使用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>

  

 

posted @ 2018-06-29 19:13  Jin同学  阅读(5942)  评论(0编辑  收藏  举报