标签:
继续今天理解一对多(多对一)双向关联。由于是双向关联,所以一对多和多对一是同一种情况。
还是用person和address的例子。一个person有多个address。这次有点复杂,把实体类的结构贴出来:
public class Person1nfk_sx implementsSerializable {
private int personid;
private String name;
private int age;
private Set addresses=new HashSet();
public class Address1nfk_sx implementsSerializable {
private int addressid;
private String addressdetail;
privatePerson1nfk_sx person1nfkSx;
区别于一对多(一个person对应多个address)的单向关联,这次的双向关联,在adress中加了person的对象作为address的成员变量。
一对多双向关联有两种方式:外键、连接表
一对多 外键 关联配置(如下):
<hibernate-mapping> <class name="com.lavasoft.sx._1_n_fk.Person1nfk_sx" table="PERSON_1nfk_sx"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--映射集合属性,关联到持久化类--> <set name="addresses" inverse="true" cascade="all"> <!--column用于指定外键列名--> <key column="personid" not-null="true"/> <!--映射关联类--> <one-to-many class="com.lavasoft.sx._1_n_fk.Address1nfk_sx"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="com.lavasoft.sx._1_n_fk.Address1nfk_sx" table="ADDRESS_1nfk_sx"> <id name="addressid"> <generator class="identity"/> </id> <property name="addressdetail"/> <!--映射关联属性,column属性指定外键列名--> <many-to-one name="person1nfk" class="com.lavasoft.sx._1_n_fk.Person1nfk_sx" fetch="select" cascade="save-update"> <column name="personid" not-null="true"/> </many-to-one> </class> </hibernate-mapping>
一对多 连接表 关联配置(如下):
<hibernate-mapping> <class name="com.lavasoft.sx._1_n_tab.Person1ntab_sx" table="PERSON_1ntab_sx"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--映射集合属性,关联到持久化类--> <!--table="join_1ntab_sx"指定了连接表的名字--> <set name="addresses" table="join_1ntab_sx" cascade="all"> <!--column="personid"指定连接表中关联当前实体类的列名--> <key column="personid" not-null="true"/> <!--unique="true"表示当前实体类是"1",不是"n"--> <many-to-many column="addressid" unique="true" class="com.lavasoft.sx._1_n_tab.Address1ntab_sx"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="com.lavasoft.sx._1_n_tab.Address1ntab_sx" table="ADDRESS_1ntab_sx"> <id name="addressid"> <generator class="identity"/> </id> <property name="addressdetail"/> <!--映射关联属性,column属性指定外键列名--> <join table="join_1ntab_sx" inverse="true" optional="true"> <key column="addressid"/> <many-to-one name="person1ntab_sx" column="personid" cascade="all" not-null="true"/> </join> </class> </hibernate-mapping>
*****一对多 外键 关联*******
采用外键关联,不难想象,是把person的主键值作为address表的外键列(这是因为一个person可以有多个address,person具有唯一性,将person的主键存到address的中,每个address都只有一个person的主键值,易存取和查询。反过来,将address存到person中,一个person有多个address,若将所有address的主键值存到对应的person行中,取出后还要将多个address解析成一个个的形式,再进行查询;由于主键的唯一性,不允许我们复制同一个person行,也就否定了这样的想法:复制同一个person行,每行只有一个address的主键存进去)。
既然是把person的主键值作为address表的外键列,那person表的配置是和一对多的单向关联差不多的。都是写set标签,里面写key标签,然后来个one-to-many的标签。
有人可能发现了,这里的set标签里没写table=“”,按照上篇写的配置,应该写上将person的主键放到哪个表里面。这里没写也算是验证了上篇说的验证机制。再回顾一下:当hibernate看到set时,还不确定是外键方式还是连接表方式,即使我们把table的值写上address表的表名,它现在也是不知道的,它在看到我们选择使用的下一个标签one-to-many后,才知道我们是外键关联。所以上篇说的验证机制是:根据table所指的表名和one-to-many中calss的类,判断是不是该calss类所对应的table表。如果我们不在set中写table,那hibernate就会直接根据class找到该表,然后插入一列叫做key标签中的column,也就是叫做personid,它最为address的外键,在address和person中建立了联系。
现在person能关联到到address了,靠的是one-to-many标签(第二篇说过one-to-one与many-to-one的异同点,这里我认为one-to-many、many-to-many与many-to-one作用是一样的)。接下来就是配置address使address能通过已经搭建好的桥梁关联到person。
很显然,对address就要用many-to-one标签了,name="person1nfk"是指,在address类中有个叫person1nfk的成员变量,我要告诉hibernate,你关联查询后要把查询后的结果封装好赋值给person1nfk。class="com.lavasoft.sx._1_n_fk.Person1nfk_sx",既说明了person1nfk的类型,也是说要去哪张表关联查询(class="com.lavasoft.sx._1_n_fk.Person1nfk_sx"所对应的表,也就是person表)。
columnname="personid"是指,要hibernate根据address的这一列作为外键,关联查询person表。这里要注意column name="personid"要与person表中写的<keycolumn="personid" not-null="true"/>相对应。若address与别的表也有外键关联,那么columnname=若指定错了列名,就会出现错误。
*****一对多 连接表 关联*******
连接表关联的方式中,person表的配置也是一样,但这里可以看到set中有table了,这里是必须要指定了,因为连接表可没有类和它对应,key表示在中间表join_1ntab_sx中有一列叫做column="personid",里面放的是person的主键值。many-to-many用unique="true"表达了一对多的含义(感觉可以直接使用one-to-many标签),column="addressid"指在中间表join_1ntab_sx中有addressid这一列,并且personid的一对多的“多”指的就是column="addressid"。既然是中间表,存放的肯定都是主键,那这个addressid是哪个表的主键呢?就由class指定。同时,将来关联查询后,很能根据这个class将数据封装返回。
接下来是addressid表的配置,由于它也要关联连接表,所以使用了join标签。
同样<keycolumn="addressid"/>把主键值放到连接表,那一列就叫addressid,这与上面配置的得一样。<many-to-one name="person1ntab_sx" column ="personid"> name="person1ntab_sx"指的是address实体类中叫做person1ntab_sx的变量(感觉这里的many-to-one是可以写class属性的,经过实验确实可以写calss,如果要写的话就写personid类)column ="personid"指关联第三方表后,查第三方表的personid列,根据查出来的主键去person表中找到数据,并封装,返回赋值给name="person1ntab_sx"的变量。
如果这里写了class就好理解了,查到personid后,根据class对应的表,也就是person表,再去person表中找数据,但这里省略了,也就说明这个class不是必须的,那hibernate去查personid列找到主键值后,是怎么知道要去person表中根据personid查数据呢?所以说关于关联这块,千丝万缕联系太多。我们只能这样想,开发框架的大神并仅仅不是根据这个class来找,当已经在personid和person建立联系后,有没有class就不重要了,这并不是说所有的class都可以不写。
personid和person的联系建立是由于在person表配置时:<keycolumn="personid">。我们已经知道hibernate够聪明,知道要把person的主键放到连接表,只让我们指定列名,我们有理由相信,hibernate同时在这时候也把personid这个列名和person表建立了联系,当我们根据addressid在连接表查到对应的personid时,hibernate一看,咦,这个personid还与person表有联系,它就会去person表继续查数据,然后返回。
******参考资料***************
http://lavasoft.blog.51cto.com/62575/39398/ 强烈推荐先看,博文写了14种情况下的配置,我就是看了这个再结合其他资料摸索的规律
http://blog.sina.com.cn/s/blog_62f0eaa80101bpaf.html
http://blog.sina.com.cn/s/blog_62f0eaa80101bpah.html
http://blog.csdn.net/sanjy523892105/article/details/7061602
http://blog.csdn.net/linminqin/article/details/6324567
http://blog.csdn.net/jialinqiang/article/details/8704538
标签:
原文地址:http://blog.csdn.net/g_thinking/article/details/51896514