Hibernate多对多关联映射和继承映射

多对多关联映射

1、多对多单向关联映射:

    如同一般的数据库设计,多对多的关系需要一个第三方表来维护关系,Hibernate中的映射关系也一样,需要一个中间表一样来维护关系,Hibernate会自动生成中间表。使用<many-to-many>标签来表示多对多的关联,采用集合的方式来映射字段。

   单向关联的映射如下图所示:


    用户User类:在User类中持有对Role的引用,采用Set集合方式,其映射文件如下:

<hibernate-mapping>
	<class name="com.bjpowernode.hibernate.User" table="t_user">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<set name="roles" table="t_user_role">
			<key column="user_id"></key>
			<many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

    在<set>标签中的table就是中间表的名称,key值是在中间表中添加一个字段,名称为user_id,<many-to-many>标签是告诉Hibernate,中间表维护的另一个关系是哪个,column是在中间表中添加一个role_id字段。

    由上面的映射文件可知,多对多的关系映射,需要一个中间表来维护,在中间表由有两端的主键组成。因为在单向关联中,只有用户一端持有对角色一端的引用,所以我们可以在用户一端查看都有哪些角色,但是在角色下面就不知道有哪些用户了。下面采用双向关联的关系进行映射,这样在两端都可以相互引用了。

2、多对多双向关联映射:

双向关联是两端都持有对方的引用,在User类中有Role放的引用,在Role方有User的引用,都是采用Set集合的方式进行的。映射文件如下:

<hibernate-mapping>
	<class name="com.bjpowernode.hibernate.User" table="t_user">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<set name="roles" table="t_user_role">
			<key column="user_id"></key>
			<many-to-many class="com.bjpowernode.hibernate.Role" column="role_id"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

    中间表名称为t_user_role,在中间表中加入一个字段user_id

<hibernate-mapping>
	<class name="com.bjpowernode.hibernate.Role" table="t_role">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<set name="users" table="t_user_role">
			<key column="role_id"></key>
			<many-to-many class="com.bjpowernode.hibernate.User" column="user_id"></many-to-many>			
		</set>
	</class>
</hibernate-mapping>

    同样维护的中间表为t_user_role,在中间表中添加的字段为role_id,这里关于中间表的信息,两个映射文件中的表名称和字段名称要一致,否则维护的关系就会发生混乱,造成数据冗余。

继承映射

   如下就是继承的UML图:

    Hibernate的框架设计同样也是基于面向对象的,自然离不开面向对象最主要的特点,继承,在Hibernate中存在三种继承关系的映射:

1、单表继承:每棵类继承树使用一个表

2、具体表继承:每个类一个表

3、类表继承:每个具体类一个表

下面我们介绍这三种继承结构:

   单表继承:

      所谓的单表继承就是把这三个对象放在一张数据表中存储,所得到的数据库表:

    我们把不同类的信息放到同一张表中,就需要不同的字段对不同类信息有一个标识,用来区分是哪类的信息,例如,这里的Type就是这个标识,P代表Pig类,B代表Bird类。

单表继承的映射文件如下:

<hibernate-mapping package="com.bjpowernode.hibernate">
	<class name="Animal" table="t_animal" lazy="false">
		<id name="id">
			<generator class="native"/>
		</id>
		<discriminator column="type" type="string"/><!-- 这样会在
		t_animal表中加入一个type字段,类型为字符串型 -->
		<property name="name"/>
		<property name="sex"/>
		<!-- 子类映射 -->
		<subclass name="Pig" discriminator-value="P">
			<property name="weight"/>
		</subclass>
		<subclass name="Bird" discriminator-value="B">
			<property name="height"/>
		</subclass>
	</class>
</hibernate-mapping>

    父类用<class>标签定义,<discriminator>是用来指定区分字段的名称和类型。子类映射使用<subclass标签discriminator-value属性是区分字段的值。

    这种继承策略的映射文件关键就是父类使用<class>标签定义,子类采用<subclass>标签定义。

  具体表继承,这种方式采用每个类一张表继承,形成的数据库表如下:

    我们把父类和子类的信息都单独的放在一张表中,每个表中的信息都是自己独有的信息,映射文件如下:

<hibernate-mapping package="com.bjpowernode.hibernate">
<!-- 每个类一张表的映射 -->
	<class name="Animal" table="t_animal">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>
		<property name="sex"/>
		<joined-subclass name="Pig" table="t_pig">
			<key column="pid"/>
			<property name="weight"/>
		</joined-subclass>
		<joined-subclass name="Bird" table="t_bird">
			<key column="bid"/>
			<property name="height"/>
		</joined-subclass>
	</class>
</hibernate-mapping>

    这种映射父类同样采用<class>标签,但是不需要在使用<discriminator>标签了,子类则使用<joined-subclass>标签,其中需要一个<key>标签来指定子类和父类之间是通过哪个字段联系的。

  类表继承:最后一种继承映射的方式是每个具体类一张表,如图:

   映射文件如下:

<hibernate-mapping package="com.bjpowernode.hibernate">
	<class name="Animal" table="t_animal" abstract="true"><!-- 设置为抽象的这样就不会在生成这个表 -->
		<id name="id">
			<generator class="assigned"/><!-- 生成策略为手动方式 -->
		</id>
		<property name="name"/>
		<property name="sex"/>
		<union-subclass name="Pig" table="t_pig">
			<property name="weight"/>
		</union-subclass>
		<union-subclass name="Bird" table="t_bird">
			<property name="height"/>
		</union-subclass>
	</class>
</hibernate-mapping>

    这种策略的映射文件子类采用<union-subclass>标签定义,子类包含的表既包含了从父类继承下来的属性,又包括自己的属性,在<union-subclass>标签中不要指定key值,设置主键的生成策略为assigned手动方式。虽然在这个标签中只有子类的属性,但是因为它继承了父类,所以在映射数据库表的时候会自动映射父类的属性。

    这三种映射各有优缺点,根据数据库的设计三范式,我们一般采用第三种方式,减少数据库冗余。采用单表继承时父类使用<class>标签,子类使用<subclass>标签,采用具体表继承父类使用<class>标签,不需要使用<discriminator>标签,子类采用<joined-subclass>标签,需要设置key值,采用类表继承,父类采用<class>标签定义,子类使用<union-subclass>标签,其中的属性只有子类的独有属性,主键的生成策略采用手动设置。








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值