2.另一类常见的标记是建立表与表之间的关系。这类标记暂叫“关系标记”
; h/ |: h( _1 C1 r$ e. f
7 m: C/ T' a% t
' D% ?( p/ E. [& F! J" b2.0 “关系标记”有: one-to-one, many-to-one, set+one-to-many, set+many-to-many
! l1 }8 n* V( @1 u1 g- y
2 o( V3 U* L4 H6 U2 g+ b; M4 ^. M' O% q" j& ?+ R
2.1
hibernate mapping中建立的表与表之间的关系和数据库中表与表之间的关系无任何瓜葛,互无影响。 ; X; Z; v6 v; ~8 }3 X2 o
前者暂叫“cfg表关系”或“config 表关系”, 或者叫“db表关系”或“database 表关系”
' l" P) A8 Z* V+ |" @. I% A2 @ 不过,cfg表关系常常参照db表关系来建立。
) V! P1 j1 |) `
8 D) V, N& f' Y+ y6 ^% s/ C
( h/ F/ ^1 g+ T) H, K- G; x' ]" F
2.2 一个关系标记对应一个属性,但该属性表达“表与表的关系”,而不与字段对应。这类属性暂叫“关系属性”
1 \, x' V2 Q& E; N: s) f! _- C
(1)这就表示更新本表的字段时,不考虑这些关系属性;
/ Y' K* i$ ^1 ` (2)更新本表的同时,也可能要同时更新关系表,这时关系属性起作用。
4 _; \) I6 `$ m/ A) z
7 q; R1 U+ A# O/ i& u6 B
6 h1 ]' r) z* I4 Y5 l2.3 准则:"cfg表关系"没有相互性。
8 T3 A4 l) y/ ?! M2 w 表mainTable 和 表relationTable,
' F% d) O3 C# }- G 在mainTable的mapping文件中建立与relationTable的many-to-one的"cfg表关系" 。
! B" n @. `4 C' D
这不表示relationTable与mainTable有one-to-many的"cfg表关系"
* x8 e6 H- H. m- R& S9 x 对relationTable的pojo对象进行数据库操作完全不受这个"cfg表关系"影响,就像没有这个关系一样。
! u- g+ x) ^3 e- { 对mainTable的pojo对象进行数据库操作,可能会根据这个"cfg表关系"更新mainTable表和relationTable表
& M7 p( l" G# l$ p9 g: H5 F" q0 T6 b9 a' M+ u8 @3 k
, B/ j/ w6 T+ D& r6 b 这点与"db表关系"不同,比如在mainTable中建立了一个指向relationTable的foreign key,
' M& T6 T$ U7 s$ v. n
那么往mainTable中插入一个foreign key 不存在的记录是不容许的,
8 p3 g. H( [, A& f) v* R
从 relationTable中删除一条记录,而这条记录mainTable中有记录关联它,那么删除会 导 致 异常。
; d4 t! F7 g; ? G# M) a* d) b
; |( C$ ~9 \/ ^& M8 q
; w o& |1 f# K9 q& c 这条准则很重要。
0 P6 t0 |5 O8 K% [; @! M 这表示一个mapping文件中建立的"cfg表关系"不会影响其它mapping文件中的"cfg表关系",
) R, h% _ C& B: W( n3 ^! _8 X
,反过来,它也不受其它mapping文件中的"cfg表关系"的影响。
, t1 n" k& M9 H 这意味着一条"cfg表关系的"的作用是可预见的,其作用由它所在的mapping文件确定的。
3 M- \* S6 B% i
2 j: K0 t- t$ O: S3 R/ W
8 c& F6 J$ D+ i# {$ S
如果relationTable想与mainTable有one-to-many的"cfg表关系",则需在relationTable的mapping文件中
# p, B5 |# }+ o0 [6 z0 q 用oneToMany标记显示地建立这种关系。
7 C- Z x) X# f. h- r0 N2 [9 C- v! t/ n4 m: |. s
9 T: ~8 f: W+ o- m e# p/ L extend: 属性inverse=true的"cfg表关系"叫"bidirectional association"(双向关系),这个属性并不会破坏这条准则。
; F7 E/ _( M& W* m& I4 l3 d6 B
后面会详细 讨 论 inverse属性。
8 x q- q: u+ ^* ?+ Q+ K; }2 c ~) \+ O5 \, r# R5 r
( {+ O- O: g3 @& u; L
! {* L0 z) r2 `, C+ g' l# D7 j4 }, C) }
2.4 "cfg表关系"( mainTable -- relationTable )有 以 下 几 种情况:
# d+ P+ U" T6 L. l: Q (1)one-to-one
* {& d8 x% V: M! ?: R 表mainTable的主键对应relationTable的主键,
0 U _6 {; g- g
多个字段作主键时,按照在mapping文件中字段出现的顺序一一对应(如果字段数不同 会 exception)
+ y1 r& Z2 ^- Z8 a$ r
: p( Z( |! g. z3 A+ u7 j: a- J* x
! X m( Q; y& _9 p1 \$ U- h
eg:配置Teacher表的mapping文件:
复制内容到剪贴板
代码:
<one-to-one name="wife"class="db.Teacher"/> (这个配置的意思是"老师的老婆是一个老师") (2)many-to-one
. j' }3 A! k9 A. _7 d
这个标记既属于“映射标记”又是“关系标记”。它有update和insert属性即是 明 证。
$ g& G/ P+ _ X. z7 K$ [" G J* u' p1 R2 J8 k
- d& u" G( v7 k& i; n 表mainTable的一些字段对应relationTable的主键
$ Q% a1 R! t" O, C, p; Z6 u/ [' _9 Y
在many-to-one标记中要声明哪些字段对应relationTable的主键
! h7 n$ i; C- A+ X. ^% n
! v2 f! H% {. b3 ^" m. \' m
$ m) R% ]$ y, l( y, y" \8 G7 }1 U% Y eg:配置schoole表的mapping文件:
复制内容到剪贴板
代码:
<many-to-one name="address" class="db.Address">
<column name="SCHOOLE_ADDRESS"/>
</many>(school表的字段SCHOOLE_ADDRESS对应address表的key(字段name))
- c* K3 ?* _4 |7 P* U
; {1 h$ m4 @; Y4 K' C5 l) z0 [
0 s; [; C* \7 ]. @ (3) one-to-many + set
# o5 r8 g0 g K3 `3 A2 c x6 F 表mainTable的主键对应relationTable的一些字段
8 o$ M% f2 D1 d' B
在many-to-one标记中要声明主键对应relationTable的哪些字段
4 W" z5 K) d, Y- \' w
$ @% I4 z: K5 C
: \0 }1 T4 ^1 m" D( P6 @. N eg:
- @* H9 S* _5 r+ g% b
配置address表的mapping文件
复制内容到剪贴板
代码:
<set name="schooleSet">
<key>
<column name="SCHOOLE_ADDRESS"/>
</key>
<one-to-many class="db.Schoole"/>
</set>从(2)和(3)的例子中可看出many-to-one和one-to-many的一些相似:
s) I$ m ]$ l E( N- t! v) I
1.one方的主键和many方的部分字段对应 9 C* D/ L* w1 X2 A! i$ f
2.须提供建立对应关系many方所需的字段。
; G( b+ O- a5 |# S- N7 M$ w
% W, S% W0 t% N( Z# L+ O( f) _6 a$ S. F+ [1 G
(4)many-to-many + set
& v' h$ x4 ^' ]. ~0 L 需要一张表来记录many-to-many关系, 这张关系表是双方主 键 所 含字段的集合。
# K# t( ]# Y8 R: n0 E$ S% A 在many-to-many标记中要说明“一方主键对应的字段, 多对多关系表, 另一方主键对应的字段”
3 U9 y3 N; _7 {/ k! _; J+ d) T# U7 H; M7 [& q; u- n3 @
$ N6 w8 z1 v+ `' M( a1 \ eg: teacher和student的多对多关系
: A9 D5 P0 P$ e1 Z* O
配置teacher表的mapping文件
复制内容到剪贴板
代码:
<set name="studentSet" table="TEACHER_STUDENT">
<key>
<column name="TEACHER_ID"/>
</key>
<many-to-many class="db.Student">
<column name="CARD_ID"/>
</many-to-many>
</set>关系表TEACHER_STUDENT含两个字段:TEACHER_ID, STUDENT_ID)
) I# Z' O- M) v+ C/ K1 s! y
+ E+ \+ s! S! J, l d- ?5 D
6 @$ a7 n: h% c ~3 i% T! ] 从(3)和(4)的例子可以看出one-to-many和many-to-many的一些相似性:
1 @' Y3 H m6 B `
1. 结 构 相 似,key子标记都提供了主 键 所 对应的它表的字段
8 Y/ c+ [3 [, d1 G& P" S1 ] 2.由于多了一个关系表,所以set标记多了属性table
W U# \2 x- x) ^6 K" a/ x 3.由于relationTable也要声明它的主 键 所对应的它表的字段,故many-to-many标记多了column属性
, j9 Y9 M u% u3 |, i8 a
+ V: w2 }+ ]# n; o' \( t8 ~6 d( K5 [& h) p) Y3 {4 B0 x) O
这四个标记都有一个共同的任务:将双方的部分字段一一对应起来(many-to-many由于关系表的出现,字段的
% c& j5 T2 y; z5 X9 w 对应也是一一对应的),就好像架起一座桥,桥的左边是mainTable的字段,桥的右边是relationTable的字段,
+ w8 j6 f6 c; }2 ^( E' s- g
把这部分字段叫做“桥字段”,字段对应的属性是“桥属性”。桥字段与普通的字段的区别是,
! K8 T0 k4 d3 j1 ^7 [) y3 M1 M5 Y hibernate要保证mainTable与relationTable中对应的桥字段的值相等。
9 f/ h( A. l- G. q& o# [' f5 {5 b- @1 {4 T: |- C$ S
9 p. r3 i" u8 ^
$ _& D8 b) g) w: v) Q8 N' X
g0 s+ K! Z( e4 [$ U4 P7 ~2.5 在查询一个pojo时,如何 得 到 它的关系属性
& ^& l( z, n, h
关系标记对应的关系属性要么是一个pojo(对one-to-one和many-to-one), 要么是pojo的集合(对
9 E$ Z3 b& ]& T) @8 N one-to-many,many-to-many而言)
! g1 C$ T5 n+ l) o
) [/ X& @) s! b$ o* y- U! s/ [3 m8 o) h1 E
hibernate在查询时,它会根据关系标记生成一个sql语句,从relationTable中查出满足条件的记录,
' k2 U/ ^7 V" _% l, F3 x 然后依照relationTable的mapping文件生成relationTable的pojo.
, R2 K6 i% v) Q. t5 w0 m4 K. y
在2.4中可看出,关系标记已给出两个表的字段是如何对应,hibernate可精确地生成sql语句。
) g" u! d; ~( k& d
' t1 q& u- F( a! Z4 J) s6 M3 T
8 y3 P( }# f% i% E+ W' [3 M# d7 b extend: 由关系属性可能是一个pojo,而一个pojo又可以有 自 己 的关系属性,其结果是hibernate生成一个pojo时,
+ z) S( s" C) |' P0 L% j7 R7 ? 藉由该pojo的关系属性, 得 到 一个pojo网。这个不难理解,因为hibernate对表间的“cfg表关系”了 然 于 胸。