标签:
接上篇,开始一对多单向关联。由于多对一的单向关联已经在(1)中说过,就不再说了,主要思想就是一对一是使用了more-to-one多对一的特殊形式,利用unique=“true”转换成特殊的一对一来使用。
说明:一对多仍然使用person和address的例子。在一对多单向关联的例子中,一个person可以有多个address,所以在person类中有一个set集合属性的成员变量,集合里面存的是address类型的变量。
一对多外键 单向关联
由于是一个person可以有多个address,所以不能是在person表中增加一列存放address,而是要在address表中增加一列存放preson的主键作为address的外键。(从主键的唯一性考虑,也能达到这种共识)
建议把两种配置粘贴到两个txt中,对比着看
一对多 外键 单向关联配置(如下)
<hibernate-mapping> <class name="com.lavasoft.dx._1_n_fk.Person1nfk" table="PERSON_1nfk"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--映射集合属性,关联到持久化类,inverse="false"表示主控端在Person1nfk端,lazy="false"表示不采用延迟加载--> <set name="addresses" table="ADDRESS_1nfk" cascade="all" > <!--确定关联的外键列--> <key column="personid"/> <!--用以映射到关联类属性--> <one-to-many class="com.lavasoft.dx._1_n_fk.Address1nfk"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="com.lavasoft.dx._1_n_fk.Address1nfk" table="ADDRESS_1nfk"> <id name="addressid"> <generator class="identity"/> </id> <property name="addressdetail"/> </class> </hibernate-mapping>
一对多 连接表 单向关联配置(如下)
<hibernate-mapping> <class name="com.lavasoft.dx._1_n_tab.Person1ntab" table="PERSON_1ntab"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--映射集合属性,join_1ntab是连接表表名--> <set name="addresses" table="join_1ntab" > <!--“column="personid"”确定PERSON_1ntab表关联到连接表的外键列名--> <key column="personid"/> <!--“column="addressid"”关联PERSON_1ntab表的Address1ntab对象的id在连接表中的列名--> <!--“unique="true"表示1-N,Person1ntab是1,Address1ntab是多”--> <many-to-many column="addressid" unique="true" class="com.lavasoft.dx._1_n_tab.Address1ntab"/> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="com.lavasoft.dx._1_n_tab.Address1ntab" table="ADDRESS_1ntab"> <id name="addressid"> <generator class="identity"/> </id> <property name="addressdetail"/> </class> </hibernate-mapping>
******一对多 外键 单向关联******
同样,由于是单向关联的,address不用特别去关注,就是正常的理解。
对person表,一行一行的看,前面都是普通的写法,很容易就理解了,关键是到<set>标签怎么理解。
由于person类中有一个set集合,所以hibernate设计者将标签叫做set,等到hibernate读到这个标签的时候,就会知道现在配置的这个表是符合一对多的模型的,并且是one-to-more中的one的一方。(很简单,只有one的一方才会把more的一方以set集合的形式存储)
但hibernate不知道的是,这个一对多是使用外键,还是使用连接表,是单向还是双向。
所以hibernate继续往下读,看到name和table就大体知道,将来我要对关联table这个表进行查询,得到的结果赋给叫做addresses的set集合变量。
既然hibernate知道要进行关联查询,那肯定得使用本表的主键与其他表建立联系、搭建桥梁,所以hibernate很聪明的会在table=“”引号中的表内,建一个列,存放本表的主键值,所以我们要做的就是给它命名,这就需要column了。
接下来就是使用one-to-more标签了。其实如果你们没有看到下面的使用连接表的配置的话可能对这个标签没有疑问,就是一个person对用多个address,所以是one-to-more标签。
在这里,我要说一下我发现的规律:就像上面我说的,hibernate看到set标签,只是知道要关联查询了,但不知道是外键查询还是连接表查询(大家可以在写完set后,按alt+/ 看提示中one-to-more与more-to-more都可以)。所以,要规定一下,因为我们知道我想要用外键的方式或连接表的方式,所以根据我们自己的需求,如果是外键方式,就用one-to-more,如果是连接表就用more-to-more。
如果写反了,虽然语法上没问题(我认为),但其实hibernate在运行时是可以知道你是用的外键还是连接表(还是我认为它会知道,起码逻辑上可以实现这样的判断),这是因为我们在one-to-more或more-to-more标签中有class属性,如果hibernate根据class,去找这个类有没有创建对应的表,然后看表名叫什么,与set标签中table的名字以比较就知道了。如果名字一样,那就是外键方式,如果不一样,那说明使用的是连接表。
总之,记住规律就好啦:如果是外键方式,就用one-to-more,如果是连接表就用more-to-more。
******一对多 连接表 单向关联******
有了上面的基础,连接表就好理解啦,还是到set集合后,指定table是连接表的名字,同样key里写在连接表中本表主键所在的列column叫什么名字,根据上面说的规律,我们是连接表的方式,用more-to-more,由于是连接表方式,现在连接表里有personid了,还需要对应的addressid,这也就是more-to-more中column的意思,unique=“true”就把more-to-more变成one-to-more了。
*********一些题外的思考*******
*******胡思乱想,现在有点混乱的就不要看了*****
做为使用者,能看到这里,理解大概的规则和流程,起码看起来不会犯糊涂了,而且有几个小规则掌握后,写起来也好些。
在第一篇感慨过,构建一个想hibernate一样的框架就是一个思维的游戏,只要自己考虑的够周全,能够实现功能,自圆其说就ok,所以在使用别人的框架的时候就很喜欢去想这些东西,会去猜设计者是根据什么规则来约束或引导程序进行判断和运行的。
就像这里(建议大家把两种配置粘贴到两个txt中,对比着看)
作为设计者在设计hibernate时,肯定会想让它更好用:比如你看,我能帮你查找数据,还能把查到的数据根据实体类自动封装成该类的对象,好用吧。当然这得有前提,首先类里面得写上get/set方法,其次,表得有对应的类,这个对应关系就在配置中体现。所以作为设计者,我要知道你哪这个实体类和哪个表是对应的,我就得强制你去给我写配置文件,还得按我的规则来,这样我才能好好分析出来,你才能用的方便。
所以,在考虑要服务大家简化维护表和表之间的关联的时候,由于牵扯太多,就得好好考虑怎么设计配置文件的书写规则了。
还是以现在的一个person对用多个address为例。
设计者作为有经验的编程人员,一看到set集合,就知道要么是一对多要么是多对多。所以设计了标签叫set,name="addresses"是告诉hibernate去该类里面找找addresses变量,看看是不是set集合,有没有对应的get/set方法。而且,要么是一对多要么是多对多的表关系,那你一定得查表,不管你是查address表还是连接表,总之得查表吧,那行我把table属性也放到set标签内。
但是到这时,我设计的hibernate还是没法确定你到底是一对多还是多对多,但我不管是那种,你都得在两个表之间建立联系才能关联查询啊,所以不管你这个table写的表名是address表还是连接表,你都得把person表的主键作为table所代表的表的外键,这样才能联系起来进行关联查询啊。而且,我知道一定是person表的主键作为外键列,所以就起个特定的标签就做key吧,你就不用写把哪一列作为外键列了,我知道是主键列了,你就给我说我的hibernate帮你把主键放到table那个表里后列名叫什么。所以key里只用写column就可以了。
现在无论是一对多还是多对多,你们共同的部分我都把规则指定好了,像表明table啊,列名啊column,现在就要确定你到底是一对多还是多对多了,就通过one-to-more与more-to-more来区分。
如果你写的是one-to-more,那好,你就是用的一对多,而且是外键关联(多对多只能通过连接表,而一对多的连接表关联就是多对多的特例)。
你用的是一对多的外键关联的话,那你的table="ADDRESS_1nfk",这个ADDRESS_1nfk就是address表了。而我作为设计者,得考虑多种情况,比如可能他配置错了table名字,根本就没找到这个表名,这种简单,直接报错。再一个就尴尬了,找到了ADDRESS_1nfk这个表名,但这个表对应的却不是address实体类,我作为设计者必须考虑到这种情况,所以我在one-to-more标签中加上class属性。如果找不到table对应的表还好,直接报错,如果找到的话,也得先等等,我得判断一下,你这个表对应的实体类是不是class=“”中的类。如果这一步校验成功,那好,我确定你就是我要找的address表,我给你增加一列personid,作为外键,到时候我会把personid和你address表关联起来查询。
再看如果写的是more-to-more,那我的hibernate就会知道你是多对多,虽然你可能会通过我设计的unique=“true”把more-to-more变成实际上的one-to-more,不过没关系,关键在于你是用连接表关联查询。作为连接表就得有既有你person表的主键也有address表的主键。
所以同样的道理,有了key标签。然而address表的主键怎么设置进连接表中呢,因为是的hibernate是在你写了more-to-more标签之后才知道是用连接表,在此之前还不能对连接表设置,所以就在more-to-more标签中设置吧,就有了column="addressid",这样就算是在连接表中加了一列。但是我的hibernate只知道要加一列,而且我的hibernate已经知道是连接表了,肯定表里存的是各表的主键,唯一的问题就是不知道addressid这一列的数据从哪里来。所以有了class属性。我的hibernate找到class对应的类,然后看这个类有没有创建对应的表,有的话把表的主键拿到连接表的addressid列中。
这里的class就没有上面one-to-more中那样帮助hibernate判断的功能啦,因为使用more-to-more后,hibernate知道是用连接表,就会看table="join_1ntab"这个名字是否被别的表占用了,如果有的话(就有两种选择,是直接覆盖还是选择报错),如果没有的话,那我的hibernate正好帮你创建这么一个连接表。
下面是参考的资料:
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/51886977