Hibernate映射详解(五)--多对多关联映射 .
实体关系图
表格关系图
当关系两方有一端为一时,我们让多的一端维护关系,可以减少数据的冗余,提高效率。那要是多对多的话,如果还在某一方维护数据,那缺点就一点都没有避免。那怎么解决这个问题呢?我们呢采用第三张表格来维护这个关系。即上图中间用户角色表。将关系两方的主键抽离出来放到第三张表中。最大程度的减少冗余性。看一下具体实现。
实体类实现:
publicclass User {
privateintid;
private Stringname;
privateSetroles; //关联属性 …省略get,set方法 } |
publicclass Role {
privateintid;
private Stringname; …省略get,set方法 }
|
对应的映射文件实现
user.hbm.xml <hibernate-mapping> <classname="com.bjpowernode.hibernate.User"table="t_user"> <idname="id"> <generatorclass="native"/> </id> <propertyname="name"/> <!--下面这段配置实现了生成第三张表,将user主键与role主键关联起来 --> <setname="roles"table="t_user_role"> <keycolumn="user_id"/> <many-to-manyclass="com.bjpowernode.hibernate.Role"column="role_id"/> </set> </class> </hibernate-mapping> |
Role.hbm.xml <hibernate-mapping> <classname="com.bjpowernode.hibernate.Role"table="t_role"> <idname="id"> <generatorclass="native"/> </id> <propertyname="name"/> </class> </hibernate-mapping>
|
看完单向,与前面一样,我们看一下双向。
实体类代码实现:
public class User {
privateintid;
private Stringname;
privateSetroles; //关联属性 …省略get,set方法 } |
public class Role {
privateintid;
private Stringname;
privateSet users; //关联属性 …省略get,set方法 } |
对应的配置文件的实现:
<hibernate-mapping> <classname="com.bjpowernode.hibernate.User"table="t_user"> <idname="id"> <generatorclass="native"/> </id> <propertyname="name"/> <setname="roles"table="t_user_role"> <keycolumn="user_id"not-null="true"/> <many-to-manyclass="com.bjpowernode.hibernate.Role"column="role_id"/> </set> </class> </hibernate-mapping> |
<hibernate-mapping> <classname="com.bjpowernode.hibernate.Role"table="t_role"> <idname="id"> <generatorclass="native"/> </id> <propertyname="name"/> <setname="users"table="t_user_role"> <keycolumn="role_id"not-null="true"/> <many-to-manyclass="com.bjpowernode.hibernate.User"column="user_id"/> </set> </class> </hibernate-mapping> |
多对多双向关联的实现原理也是新增一张表,使两端的主键联系起来。所以,在映射文件的配置时,生成的中间表名称必须是一样的,比如这里的set标签中定义的table字段t_user_role。除了表名称以外,表字段名称也必须是一样的如此处set标签中的column标签的值。
到现在,关联映射我们就已经介绍完了。通过,这么多映射的比较,他们之间确实是有几点共性的地方。
假设有关系A,B两端。若A与B有单向关联,即A—>B,则A的实体类中会有B作为他的属性。若B端为一(非多),则A中多一个B类型的属性,若B端为多,则A中多一个Set类型的集合,而它存储的类型当然为B。这跟A端是多或者一是没有关系的。那映射文件呢?若one-to-one或者many-to-one,one端name为另一端实体类中实例化的变量的名字。而若是*-to-many,则many一端name为多的一端的对象类所在的位置。哪个包下边哪个类。若实体中出现了Set类型的属性,那映射文件中对应的也会有Set标签。