hibernate中一对多和多对多关系

一对多:

                    一个部门对应多个员工,一个员工只能属于某一个部门。

                    一个客户对应多个联系人,一个联系人只能属于某一个客户。 

          建表原则:

                              在多的一方创建外键指向一的一方的主键

          客户为一,联系人为多

          创建实体类时:

    /**
     *  Customer(一)中放LinkMan(多)的集合
     */ 

    // 通过ORM方式表示,一个客户对应多个联系人
	// 放置的是多的一方的集合,hibernate默认使用的Set集合
	private Set<LinkMan> linkMans = new HashSet<LinkMan>();
	/**
	 * LinkMan(多)中放Customer(一)的对象
	 */
	// 通过ORM,一个联系人只能属于某一个客户
	private Customer customer;

          配置映射文件时:

  多的一方的中的配置文件中添加配置(在calss标签中添加):


<!-- 配置一对多的关系 -->	
	<!-- 
	   	set标签:
			name:多的一方的对象的集合的属性名称
	 -->
	<set name="linkMans" >
		<!-- 
			key标签
				column:多的一方的外键名称
		 -->
		<key column="lkm_cust_id"></key>
		<!-- 
			one-to-many标签
				class:多的一方的全路径
		 -->
		<one-to-many class="domain.LinkMan"/>
	</set>

     

一的一方的中的配置文件中添加配置(在calss标签中添加): 

<!--配置一对多的关系  -->
	<!-- 
		many-to-one标签:
				name	:一的一方在多的一方类中的属性名称
				class	:一的一方的类的全路径
				column	:在多的一方的表中的外键的名称
	 -->
	 <many-to-one name="customer"  class="domain.Customer" column="lkm_cust_id"></many-to-one>

操作:

  一对多关系保存一边不行,会报错,解决方法:级联操作

    //一对多关系只保存一边
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一个客户
		Customer customer1 = new Customer();
		customer1.setCust_name("东");
		
		//一个联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("甲");
		 
		//设置关系
		linkMan1.setCustomer(customer1);
	
		customer1.getLinkMans().add(linkMan1);
		
		//保存一边:不可以,报瞬时对象异常,持久态对象关联一个瞬时态对象
		session.save(customer1);
		
		transaction.commit();
	}

级联:

级联保存或更新:

          在一的一方的配置文件中添加配置:

                          在set标签中添加 cascade=“save-update”

/**
 * 级联保存或更新操作
 * 		保存客户级联联系人,操作主题是客户对象,需要在客户映射文件中配置
 */
public void test(){
	Session session = HibernateUtils.getCurrentSession();
	Transaction transaction = session.beginTransaction();
		
	//一个客户
	Customer customer1 = new Customer();
	customer1.setCust_name("东");
		
	//一个联系人
	LinkMan linkMan1 = new LinkMan();
	linkMan1.setLkm_name("甲");
		 
	//设置关系
	linkMan1.setCustomer(customer1);
	
	customer1.getLinkMans().add(linkMan1);
		
	//保存一边:不可以,配置级联后可以
	session.save(customer1);
		
	transaction.commit();
}

  在多的一方的配置文件中添加配置:

                          在many-to-one标签中添加 cascade=“save-update”

    /**
	 * 级联保存或更新操作
	 * 		保存联系人,操作主题是联系人对象,需要在联系人映射文件中配置
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一个客户
		Customer customer1 = new Customer();
		customer1.setCust_name("1");
		
		//一个联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("2");
		 
		//设置关系
		linkMan1.setCustomer(customer1);
	
		customer1.getLinkMans().add(linkMan1);
		
		//保存一边:不可以,配置级联后可以
		session.save(linkMan1);
		
		transaction.commit();
	}
	

级联删除:

在一的一方的配置文件中添加配置:

                          在set标签中添加 cascade=“delete”,delete和save-update可以同时存在

    /**
	 * 级联删除:
	 * 		删除客户级联联系人
	 * 		删除客户,同时删除联系人,在客户配置文件中配置级联删除:cascade=delete
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//没有设置级联删除,默认情况:修改了联系人的外键,删除客户
//		Customer customer = session.get(Customer.class, 1l);
//		session.delete(customer);
		
		//删除客户,同时删除联系人,在客户配置文件中配置级联删除:cascade=delete
		Customer customer = session.get(Customer.class, 1l);
		session.delete(customer);
		
		transaction.commit();
	}

在多的一方的配置文件中添加配置:

                          在many-to-one标签中添加 cascade=“save-update”,delete和save-update可以同时存在

    /**
	 * 级联删除:
	 * 		删除联系人级联客户
	 * 		删除联系人,同时删除客户,在联系人配置文件中配置级联删除:cascade=delete
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		
		//删除联系人,同时删除客户,在联系人配置文件中配置级联删除:cascade=delete
		LinkMan linkMan = session.get(LinkMan.class, 1l);
		session.delete(linkMan);
		
		transaction.commit();
	}

对象导航:

   前提是双方都设置了cascade="save-update"


	/**
	 * 测试对象导航
	 * 		前提:一对多的双方都设置cascade="sava-update"
	 */
	public void test5(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一个客户
		Customer customer1 = new Customer();
		customer1.setCust_name("1");
		
		//三个联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("张三");
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("李四");
		LinkMan linkMan3 = new LinkMan();
		linkMan3.setLkm_name("王如花");
		 
		//设置关系
		linkMan1.setCustomer(customer1);
		customer1.getLinkMans().add(linkMan2);
		customer1.getLinkMans().add(linkMan3);
		
		//双方都设置了cascade
		//session.save(linkMan1);//4条insert语句
		//session.save(linkMan2);//1条insert语句
		session.save(customer1);//3条insert语句
		
		transaction.commit();
	}

inverse:

        比如将2号联系人从1号客户改为2号客户,原来会发三个select语句,两个update语句,在Customer配置文件中配置inverse="true",放弃外键维护权,用来解决多余的sql语句,这样会只发送一条update语句,

    /**
	 * 将2号联系人原来归1号客户,现在在改为2号客户
	 * 		
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//查询2号联系人
		LinkMan linkMan = session.get(LinkMan.class, 2l);
		//查询2号客户
		Customer customer = session.get(Customer.class, 2l);
		
		//双向关联
		linkMan.setCustomer(customer);
		customer.getLinkMans().add(linkMan);
		
		transaction.commit();
	}

      区别:

           cascade管的是关联对象,而inverse管的是一的一方控不控制外键

多对多:

                    一个学生可以选择多门课程,一门课程也可以被多个学生选择。

                    一个用户可以选择多个角色,一个角色也可以被多个用户选择。

           建表原则:

                              创建一个中间表,中间表至少有两个字段分别作为外键指向多对多双方的主键

                

               用户和角色都是多

                创建实体类时:

                User类中有Role对象集合的属性

                Role类中有USer对象集合的属性

private Set<User> users = new HashSet<User>();
private Set<Role> roles = new HashSet<Role>();

           配置映射文件时:

                这是Role的配置文件,User的类似。

            <!-- 
    			set标签
    				name:对方的集合的属性名称
    				table:多对多的关系需要使用中间表,放的是中间表的名称
 		   	 -->
    		<set name="users" table="sys_user_role" >
    			<!-- 
    				key标签:
    					column:当前对象所对应的外键名称
    			 -->
    			<key column="role_id"></key>
    			<!-- 
    				many-to-many标签
    				class:对方的类的全路径
    				column:对方的对象在中间表中的外键名称
    			 -->
    			<many-to-many class="domain.User" column="user_id"></many-to-many>
    		</set>

        多对多关系中如果进行了双向维护关系(比如角色中添加用户,用户中添加角色),就必须有一方放弃外键维护权,一般由被动方放弃

如下:

        如果不放弃外键维护全,中间表中两个字段共同作为主键就会重复,报错。

        所以在set中添加inverse=true

    public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//两个用户
		User user1 = new User();
		user1.setUser_name("u1");
		User user2 = new User();
		user2.setUser_name("u2");
		
		//三个角色
		Role role1 = new Role();
		role1.setRole_name("r1");
		Role role2 = new Role();
		role2.setRole_name("r2");
		Role role3 = new Role();
		role3.setRole_name("r3");
		
		//设置双向关联关系
		user1.getRoles().add(role1);
		user1.getRoles().add(role2);
		user2.getRoles().add(role3);
		user2.getRoles().add(role1);
		
		role1.getUsers().add(user1);
		role1.getUsers().add(user1);
		role2.getUsers().add(user2);
		role3.getUsers().add(user2);

		//保存操作,多对多建立双向关系时,必须有一方放弃外键维护
		//一般是被动方放弃
		session.save(user1);
		session.save(user2);
		session.save(role1);
		session.save(role2);
		session.save(role3);
		
		transaction.commit();
	}

多对多级联保存(删除类似):

    /**
	 * 多对多只保存一边,会报瞬时对象异常
	 * 多对多的级联,保存用户级联角色,在用户映射文件中设置
	 * 		保存角色级联用户,在角色映射文件中设置
	 */
	public void test(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		//一个用户
		User user1 = new User();
		user1.setUser_name("u1");
		
		
		//一个角色
		Role role1 = new Role();
		role1.setRole_name("r1");
		
		
		//设置双向关联关系
		user1.getRoles().add(role1);
		
		role1.getUsers().add(user1);
		
		session.save(user1);
		
		transaction.commit();
	}

多对多关系更多的是对集合的操作

猜你喜欢

转载自blog.csdn.net/qq_40605913/article/details/81461685