空间管理 您的位置: Linux宝库 » loon » 日志

精通Hibernate之映射继承关系(三)

上一篇 / 下一篇  2008-01-15 22:53:14

表中不仅提供和Employee类的属性对应的字段,还要提供和它的两个子类的所有属型对应的字段,此外,EMPLOYEES表中需要额外加入一个字符串类型的EMPLOYEE_TYPE字段,用于区分Employee的具体类型。 Linux宝库:mm{b;|D6PO

4dOM ]"M-~-A N0 Linux宝库8Lu`+X'?UA

  图14-4 继承关系树的根类对应一个表

:EP+wP1J9o aR9vre0 Linux宝库:QQDol,u8M

  Company类和Employee类有相应的映射文件,而HourlyEmployee类和SalariedEmployee类没有相应的映射文件。图14-5显示了持久化类、映射文件和数据库表之间的对应关系。Linux宝库1`~2Ki1E0m6x0Qx

Linux宝库4cy@K"B

Linux宝库^;t9d|&g3BBZ

z+]Sn#~&O0  图14-5 持久化类、映射文件和数据库表之间的对应关系Linux宝库:kgAGL8?R

Linux宝库*S ]Pz Y|9? `

  14.2.1 创建映射文件Linux宝库9~b.S Q NR

Linux宝库vI2C"| N;c

  从Company类到Employee类是多态关联,由于关系数据模型描述了Employee类和它的两个子类的继承关系,因此可以映射Company类的employees集合。例程14-5是Company.hbm.xml文件的代码,该文件不仅映射了Company类的id和name属性,还映射了它的employees集合。

y7w@VTbCm0 Linux宝库$V)mG Cyr

  例程14-5 Company.hbm.xml

%SH;F.Q2B`!L0

y:f#e^+D(p+e$\)p0<hibernate-mapping >Linux宝库2l8`sc})p^#^2h

Linux宝库{dLB'@V8Cg

<class name="mypack.Company" table="COMPANIES" >Linux宝库"|mG}0j5e1N+T
<id name="id" type="long" column="ID">
6hp ]+U1gv0<generator class="increment"/>
m2C*SS_0</id>
Linux宝库J]g2l;S3N/V K

Linux宝库N5v{"y0AeR e{

<property name="name" type="string"  column="NAME" />
4i5io/EiZ0<set
%a ~/`v3E0name="employees"Linux宝库#B*]%MF'f1\!bW
inverse="true"
+T3h&xNm/[5^0lazy="true" >
-_}5M8B'd;b^p0<key column="COMPANY_ID" />Linux宝库 |o+b bw2wn(\I
<one-to-many class="mypack.Employee" />
a,i&tC IAM$\0</set>  

e7YQ e g?^ e0 Linux宝库&}AD OY)_ f&Q

</class>Linux宝库 Rs6~"K!h N `|+}
</hibernate-mapping>
!hAb&o t0 

%G8?kh {$HFm3M0

|*p0f+uQ*{/a3T a0Linux宝库*r#n|^&V z%q5Y r;tzp
  Employee.hbm.xml文件用于把Employee类映射到EMPLOYEES表,在这个映射文件中,除了需要映射Employee类本身的属性,还需要在 元素中映射两个子类的属性。例程14-6是Employee.hbm.xml文件的代码。

Jr|5o` ?IO2X0 Linux宝库!br'V C7jCzr

  例程14-6 Employee.hbm.xml

+Al7S5tvj{0 Linux宝库/HB0AA%y.b

<hibernate-mapping >
~m~'ZjN+F0      <class name="mypack.Employee" table="EMPLOYEES">Linux宝库p,Cr)l}
      <id name="id" type="long" column="ID">Linux宝库'K"PzQi }w&b
        <generator class="increment"/>
Kz|H+O$P(|S_M{0      </id>Linux宝库0s/GK0x0ht {9o
      <discriminator column="EMPLOYEE_TYPE" type="string"  /> 
(F;Sv0~{ ce`!m0      <property name="name" type="string" column="NAME" />

4}C D4t MA"D0 Linux宝库I5~V??6JH5M

      <many-to-one
:T0m4?"F6K|[ iEVS m\L0        name="company"
2C$}:BV6FP#P0        column="COMPANY_ID"
O I$ZW"g:`J1]0        class="mypack.Company"Linux宝库 Q|'@.T3D0~
      />

$h_n I%b;Su0 Linux宝库Hh1Y5R x)bT#T8[

      <subclass name="mypack.HourlyEmployee" discriminator-value="HE" >
VW'?0R[x0         <property name="rate" column="RATE" type="double" />Linux宝库7l(z o5u-qq3Gt R z0L
      </subclass>

S1IW#}{@0

+t2b~ K'P3^:l)fl*i0      <subclass name="mypack.SalariedEmployee" discriminator-value="SE" >
1@Q*?1nz6B-`0aF0         <property name="salary" column="SALARY" type="double" />Linux宝库Fo RU Z%p3`W~
      </subclass>
6Vwp$PP!X8M0     Linux宝库9FS'J2a6Hk,?%J ?
      </class>Linux宝库 Do0T-m$c-tT
 
m"NV'F$~NE9j Y3`0      </hibernate-mapping> Linux宝库o {2^|6LHQ@R

Linux宝库I4A.`:di5G3Wv


;m E;B rT4O0  在Employee.hbm.xml文件中, 元素指定EMPLOYEES表中用于区分Employee类型的字段为EMPLOYEE_TYPE,两个 元素用于映射HourlyEmployee类和SalariedEmployee类, 元素的discriminator-value属性指定EMPLOYEE_TYPE字段的取值。EMPLOYEES表中有以下记录:Linux宝库sx:{&c~~

u8Ct~kfi's0  其中ID为1和2的记录的EMPLOYEE_TYPE字段的取值为"HE",因此它们对应HourlyEmployee类的实例,其中ID为3和4的记录的EMPLOYEE_TYPE字段的取值为"SE",因此它们对应SalariedEmployee类的实例。

4Du0sch+D0 Linux宝库|t qL A._3X

  这种映射方式要求EMPLOYEES表中和子类属性对应的字段允许为null,例如ID为1和2的记录的SALARY字段为null,而ID为3和4的记录的RATE字段为null.如果业务需求规定SalariedEmployee对象的rate属性不允许为null,显然无法在EMPLOYEES表中为SALARY字段定义not null约束,可见这种映射方式无法保证关系数据模型的数据完整性。

pu2x!R6VM3F+^%v(q:z-S0 Linux宝库c*~~$M*x*@|1Gr+\

  由于HourlyEmployee类和SalariedEmployee类没有单独的映射文件,因此在初始化Hibernate时,只需向Configuration对象中加入Company类和Employee类:Linux宝库!f&o.vk `3b9Ml

\cb'DYEB&v0  Configuration config = new Configuration();Linux宝库6pd{B T+s|A\v

Linux宝库]D\5OH9x:G p

  config.addClass(Company.class)Linux宝库)O0cZE,`/h!u(X;C

Linux宝库]v"vg6j-yFF3M

  。addClass(Employee.class);

Aj!RpK[3J0 Linux宝库.tULe3D

  如果Employee类不是抽象类,即它本身也能被实例化,那么可以在 元素中定义它的discriminator值,形式如下:

0g3b7q)n"f%F ]0

N!M3g;\?$`+Y7o0  <class name="mypack.Employee"Linux宝库)e8W3hRk1M(T?;o

Linux宝库MS&Q4x]2T D

  table="EMPLOYEES"

s?*S;c#t@H,~0 Linux宝库z+z S t Mq/U8t._g

  discriminator-value="EE">

B~+@["]0 Linux宝库MNJ g,qe

  以上代码表明,如果EMPLOYEES表中一条记录的EMPLOYEE_TYPE字段的取值为"EE",那么它对应Employee类本身的实例。

7k3Q#w:yJ'Y.uI0

{1um*H)H!g0  14.2.2 操纵持久化对象Linux宝库R LE8m3U:dscV

Linux宝库KIbS/i

  这种映射方式支持多态查询,对于以下查询语句:

y Y)U {tyvtb0

'lgD8J-TZ:J3nc0  List employees=session.find("from Employee");Linux宝库%^#uZ,q G

Linux宝库0G3T ]Nr+\K N

  Hibernate会检索出所有的HourlyEmployee对象和SalariedEmployee对象。此外,也可以单独查询Employee类的两个子类的实例,例如:

P q!d"X:K"X4CrlT0

IfX%q8{RcV0  List hourlyEmployees=session.find("from HourlyEmployee");

(i]f$y5k c0 Linux宝库 ?+Kkagu2^2w

  本节的范例程序位于配套光盘的sourcecode\chapter14\14.2目录下,运行该程序前,需要在SAMPLEDB数据库中手工创建COMPANIES表和EMPLOYEES表,然后加入测试数据,相关的SQL脚本文件为/14.2\schema\sampledb.sql.Linux宝库ucD9N6C7K C/ZZ

.w/H-D_Fo0  在DOS命令行下进入chapter14根目录,然后输入命令:Linux宝库 ~W3y }'y9}1N

&t7Y*nFRV^t0K0  ant  -file  build2.xml  run

[k!b pK9M(~0

zxIh3rH$u~0  就会运行BusinessService类。BusinessService的main()方法调用test()方法,test()方法依次调用以下方法:

*mOF,F0B@E0

PC/s`g,|0  findAllHourlyEmployees():检索数据库中所有的HourlyEmployee对象。

rk1lP8Z0

:U-SP3n0IaV0  findAllEmployees():检索数据库中所有的Employee对象。Linux宝库8E;yo'~1O6g!M M

ui1jx_hoTZu0  loadCompany():加载一个Company对象。Linux宝库+[9|_JjB F(h

Linux宝库N0Q7X-I u&aTnf

  saveEmployee():保存一个Employee对象。

A@ON^0

(i7X"_PJ1t4@6w*n0  (1)运行findAllHourlyEmployees()方法,它的代码如下:Linux宝库F{ ?E6g!t&J

Linux宝库;{%h4S*Aj;W

  tx = session.beginTransaction();

yv(s De5eh0

.E?j:S(O3g'?5q0  List results=session.find("from HourlyEmployee");

@\/VoV$QZ0 Linux宝库&?D7\ V8f _

  tx.commit();Linux宝库q4k(O2O(V!] P1z'~)A

Linux宝库&WY*n y/KgNl

  return results;

j }Ae0R\jZ7d0 Linux宝库:ZT4GX%}e$\a8w0[ D L

  在运行Session的find()方法时,Hibernate执行以下select语句:

-Q DOjyx,Gh0

l)~C:A9Wui$L8a0  select * from EMPLOYEES where EMPLOYEE_TYPE='HE' ;

I#kP&[i%pC o"o0

3L2u)|ef8K3fA w0  select * from COMPANIES where ID=1;

kN9o%}_4Wx2D0 Linux宝库(\"Zem Hh

  在加载HourlyEmployee对象时,还会同时加载与它关联的Company对象。Linux宝库.D"W Ax*K-_i(d;_

Linux宝库m/F4F*l8a R p:NlWe

  (2)运行findAllEmployees()方法,它的代码如下:

dmnN,^$` C1m,x0 Linux宝库[ h R3Ju EMD

  tx = session.beginTransaction();Linux宝库\Rm _? Z+y|

Linux宝库6ea-m2L)sUb:I w

  List results=session.find("from Employee");Linux宝库$z*^ f#^&QOT r;f#n

5a$FFW @#jP S3U9M0  tx.commit();

'FJ z Knx2{0 Linux宝库2v D-\5g*dY

  return results;Linux宝库|:m/Xi.Zn0ar

Linux宝库#Px2g5V(ut5h Xu;|

  在运行Session的find()方法时,Hibernate执行以下select语句:Linux宝库\D DL/|VM$}3a9x.G;h

Linux宝库4P(d\*w)|?;UM@u Z

  select * from EMPLOYEES;

Hh+O(Ui"o$y8DE.q0 Linux宝库It1Ok"kp;f4P{"p#~

  select * from COMPANIES where ID=1;

;[na7E X$?o0 Linux宝库'`&h e:J5L

  在这种映射方式下,Hibernate支持多态查询,对于从EMPLOYEES表获得的查询结果,如果EMPLOYEE_TYPE字段取值为"HE",就创建HoulyEmployee实例,如果EMPLOYEE_TYPE字段取值为"SE",就创建SalariedEmployee实例,这些实例所关联的Company对象也被加载。

mf6p{t B0

TBp])F9_ iRmd0  (3)运行loadCompany()方法,它的代码如下:

(Wj!_(gA%f0

6\~0k qWBI0  tx = session.beginTransaction();Linux宝库 hjg"@Q"B[p3w

Linux宝库dtfbWH^1nw @%Z

  Company company=(Company)session.load(Company.class,new Long(id));

#O:lS-v5A6A m p%f Y0

"B6fq&KLSu0  Hibernate.initialize(company.getEmployees());

+{P1v,Hwi THu7y&b0

v^0xh3rv:u@j0  tx.commit();

?!bn5NYC?j J0 Linux宝库6[s?9b"th"G ny1A

  这种映射方式支持多态关联。如果在Company.hbm.xml文件中对employees集合设置了立即检索策略,那么Session的load()方法加载的Company对象的employees集合中包含所有关联的Employee对象。由于本书提供的Company.hbm.xml文件对employees集合设置了延迟检索策略,因此以上程序代码还通过Hibernate类的静态initialize()方法来显式初始化employees集合。

| Rg,SP?2W0 Linux宝库8Ga/X/h;D&x:m$W3G8Rc

  (4)运行saveEmployee(Employee employee)方法,它的代码如下:

aH.@VLy6zu0

3dWn8Xm0  tx = session.beginTransaction();

4u*A%JAy(t0

)\]c|^,t1d0  session.save(employee);Linux宝库X_7{z9Z`:X1n:xp`

Linux宝库M)b;r6}PX f

  tx.commit();

/Mj\NO'dl]0

XIbX\uK8Y%e0X0  在test()方法中,创建了一个HourlyEmployee实例,然后调用saveEmployee()方法保存这个实例:Linux宝库0KGtxfO&Er

G&p-?b0^0  Employee employee=new HourlyEmployee("Mary",300,company);

:H1]$PYz0

3x6G6i,dV0  saveEmployee(employee);

2~z1cC QVJZ.P o0 Linux宝库 r?fx-ilt

  Session的save()方法能判断employee变量实际引用的实例的类型,如果employee变量引用HourlyEmployee实例,就执行如下insert语句:Linux宝库 ]+{^1h5s4W v"d

Linux宝库FLQ,Fc.L u

  insert into EMPLOYEES(ID,NAME,RATE,EMPLOYEE_TYPE,CUSTOMER_ID)Linux宝库 ?f A'D3{5L!JsY

Linux宝库i%WY*KK!^

  values(5, 'Mary ',300, 'HE',1);Linux宝库.uZ/{Ur

&_q|M)KrU0  以上insert语句没有为SalariedEmployee类的salary属性对应的SALARY字段赋值,因此这条记录的SALARY字段为null.Linux宝库fP`bffAU


TAG:

引用 删除 Guest   /   2008-07-30 18:00:02
 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

我的存档

数据统计

  • 访问量: 6351
  • 日志数: 13
  • 建立时间: 2008-01-15
  • 更新时间: 2008-01-15

RSS订阅

Open Toolbar