hibernate 一对多,多对一,一对一,多对多 映射

1.多对一映射  many-to-one

单向多对一映射(以customer--order为例)

一个customer可以有多个order,一个order只能对应一个customer

实体类中Order中存放一个Customer的对象

customer.hbm.xml映射文件

<hibernate-mapping>
	<class table="CUSTOMERS" name="com.atguigu.hibernate.entities.n21.Customer">
		<id name="customerId" type="java.lang.Integer">
			<column name="CUSTOMER_ID"/>
			<generator class="native"/>
		</id>
		<property name="customerName" type="java.lang.String">
			<column name="CUSTOMER_NAME"/>
		</property>
	</class>
</hibernate-mapping>
order.hbm.xml文件

<hibernate-mapping package="com.atguigu.hibernate.entities.n21">
	<class table="ORDERS" name="Order">
		<id name="orderId" type="java.lang.Integer">
			<column name="ORDER_ID"/>
			<generator class="native"/>
		</id>
		<property name="orderName" type="java.lang.String">
			<column name="ORDER_NAME"/>
		</property>
<!-- 映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 
		name: 多这一端关联的一那一端的属性的名字 
		class: 一那一端的属性对应的类名 
		column: 一那一端在多的一端对应的数据表中的外键的名字 -->
		<many-to-one class="Customer" name="customer" column="CUSTOMER_ID"/>
	</class>
</hibernate-mapping>


注意点:

1.1 插入语句

如果先插入一的一端(customer),再插入多的一端(order):发送三条insert语句:插入customer,order1,order2。(推荐)
如果先插入多的一端(order),再插入一的一端(customer):先发送三条insert语句,插入order1,order2,customer,再发送两条update语句。

1.2 查询语句

(1)如果先查询多的一端的对象,默认情况下只查询了多的一端的对象,没有查询关联的一的一端的对象
(2)如果需要使用到关联的对象,才会发送sql语句,
(3)由order查询customer,若session被关闭,默认情况下会发生LazyInitializationException异常
(4)取得order对象时,默认情况下,其customer是一个代理对象

1.3 删除语句

在不设定级联关系的情况下,且1这一端的对象有n这一端的对象在引用,不能直接删除1这一端的对象

2.一对多映射one-to-many

双向一对多映射(以customer--order为例)


实体类中:
Customer中放入一个Order的set  
private Set<Order> orders = new HashSet<>();
(1.声明集合类型时,需使用接口类型。因为hibernate获取集合类型时,返回的是hibernate的一个内置的集合类型
  2.需要对set进行初始化,防止空指针异常)

Order中存放一个Customer的对象


customer.hbm.xml

<hibernate-mapping package="com.atguigu.hibernate.entities.n21.both">
    
    <class name="Customer" table="CUSTOMERS">
    
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
    
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMER_NAME" />
        </property>
        
        <!-- 映射 1 对多的那个集合属性 -->
        <!-- set: 映射 set 类型的属性, table: set 中的元素对应的记录放在哪一个数据表中. 该值需要和多对一的多的那个表的名字一致 -->
        <!-- inverse: 指定由哪一方来维护关联关系. 通常设置为 true, 以指定由多的一端来维护关联关系 -->
        <!-- cascade 设定级联操作. 开发时不建议设定该属性. 建议使用手工的方式来处理 -->
        <!-- order-by 在查询时对集合中的元素进行排序, order-by 中使用的是表的字段名, 而不是持久化类的属性名  -->
        <set name="orders" table="ORDERS" order-by="ORDER_NAME DESC">  <!--一般添加 inverse="true"-->
        	<!-- 执行多的表中的外键列的名字 -->
        	<key column="CUSTOMER_ID"></key>
        	<!-- 指定映射类型 -->
        	<one-to-many class="Order"/>
        </set>
        
    </class>
    
</hibernate-mapping>


order.hbm.xml 跟之前的多对一一样

<hibernate-mapping package="com.atguigu.hibernate.entities.n21.both">

    <class name="Order" table="ORDERS">

        <id name="orderId" type="java.lang.Integer">
            <column name="ORDER_ID" />
            <generator class="native" />
        </id>
        
        <property name="orderName" type="java.lang.String">
            <column name="ORDER_NAME" />
        </property>
        
		<!-- 
			映射多对一的关联关系。 使用 many-to-one 来映射多对一的关联关系 
			name: 多这一端关联的一那一端的属性的名字
			class: 一那一端的属性对应的类名
			column: 一那一端在多的一端对应的数据表中的外键的名字
		-->
		<many-to-one name="customer" class="Customer" column="CUSTOMER_ID"></many-to-one>

    </class>
</hibernate-mapping>


注意点:

1.插入语句 insert

先插入customer,再插入order:3条insert,两条update
(因为一的一端和多的一端都维护关联关系,所以会多出两条update)
先插入order,再插入customer:3条insert,四条update
优化方案:
hibernate中通过inverse属性决定由哪一方来维护表和表之间的关系。inverse=false为主动方,inverse=true为被动方。由主动方负责维护
在没有设置inverse=true情况下,两边都负责维护关联关系
在1-n关系中,由n方负责维护有助于性能的改善
<set name="orders" table="ORDERS" inverse="true">变量名,数据库表名
<key column="CUSTOMER_ID"></key>外键的列名
<one-to-many class="Order"/>类名
<set>

2.查询语句
对n的一端的集合使用延迟加载,返回多的一端的集合是Hibernate内置的集合类型该类型具有延时加载和存放代理对象的功能
可能会抛出懒加载异常
 


3.一对一映射  one-to-one

3.1基于外键的一对一映射

一端使用many-to-one,一端使用 one-to-one

以  department--manager为例

Department实体类中放一个Manager对象

Manager实体类中放一个Department对象


department.hbm.xml

<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.foreign.Department" table="DEPARTMENTS">

        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <generator class="native" />
        </id>
        
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
		
		<!-- 使用 many-to-one 的方式来映射 1-1 关联关系  需在外键上加上唯一约束-->
		<many-to-one name="mgr" class="com.atguigu.hibernate.one2one.foreign.Manager" 
			column="MGR_ID" unique="true"></many-to-one>	        
			        
    </class>
</hibernate-mapping>

manager.hbm.xml

<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.foreign.Manager" table="MANAGERS">
        
        <id name="mgrId" type="java.lang.Integer">
            <column name="MGR_ID" />
            <generator class="native" />
        </id>
        
        <property name="mgrName" type="java.lang.String">
            <column name="MGR_NAME" />
        </property>
        
        <!-- 映射 1-1 的关联关系: 在对应的数据表中已经有外键了, 当前持久化类使用 one-to-one 进行映射 -->
        <!-- 
        	没有外键的一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段
         -->
        <one-to-one name="dept" 
        	class="com.atguigu.hibernate.one2one.foreign.Department"
        	property-ref="mgr"></one-to-one>
        
    </class>
    
</hibernate-mapping>

(1)保存操作 
建议先保存manager,再保存department。可以减少一条update语句
(2)查询操作
在查询没有外键的对象时,使用的是左外连接,一并查询出其关联对象,并进行初始化

3.2基于主键的一对一映射

department.hbm.xml

<hibernate-mapping package="com.atguigu.hibernate.one2one.primary">

    <class name="Department" table="DEPARTMENTS">

        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <!-- 使用外键的方式来生成当前的主键 -->
            <generator class="foreign">
            	<!-- property 属性指定使用当前持久化类的哪一个属性的主键作为外键 -->
            	<param name="property">mgr</param>
            </generator>
        </id>
        
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
		
		<!--  
		采用 foreign 主键生成器策略的一端增加 one-to-one 元素映射关联属性,
		其 one-to-one 节点还应增加 constrained=true 属性, 以使当前的主键上添加外键约束
		-->
		<one-to-one name="mgr" class="Manager" constrained="true"></one-to-one>
					        
    </class>
</hibernate-mapping>

manager.hbm.xml

<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.primary.Manager" table="MANAGERS">
        
        <id name="mgrId" type="java.lang.Integer">
            <column name="MGR_ID" />
            <generator class="native" />
        </id>
        
        <property name="mgrName" type="java.lang.String">
            <column name="MGR_NAME" />
        </property>
        
        <one-to-one name="dept" 
        	class="com.atguigu.hibernate.one2one.primary.Department"></one-to-one>
        
    </class>
    
</hibernate-mapping>


先插入哪一个都不会有多余的update


4.多对多映射

many-to-many

做法:使用一张中间表

以catagory--item  为例

实体类:

Category中放一个item的Set,Item中放一个Category 的Set

Category.hbm.xml

<hibernate-mapping package="com.atguigu.hibernate.n2n">

    <class name="Category" table="CATEGORIES">
    
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
    
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
        <!-- table: 指定中间表 -->
        <set name="items" table="CATEGORIES_ITEMS">
            <key>
                <column name="C_ID" />
            </key>
            <!-- 使用 many-to-many 指定多对多的关联关系. column 执行 Set 集合中的持久化类在中间表的外键列的名称  -->
            <many-to-many class="Item" column="I_ID"></many-to-many>
        </set>
        
    </class>
</hibernate-mapping>

item.hbm.xml

<hibernate-mapping>

    <class name="com.atguigu.hibernate.n2n.Item" table="ITEMS">
        
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        
        <set name="categories" table="CATEGORIES_ITEMS" inverse="true">
        	<key column="I_ID"></key>
        	<many-to-many class="com.atguigu.hibernate.n2n.Category" column="C_ID"></many-to-many>
        </set>
        
    </class>
</hibernate-mapping>
注意:

1.表名相同  2.列名交叉对应  3.一方放弃维护中间表,避免主键冲突

单向多对多时,实体类中去掉一个set,并去掉对应的映射即可(inverse="false")














  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值