This is first commit against Hibernate3 SVN.This translation is for v3.1.2.
git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@10097 1b8cb986-b30d-0410-93ca-fae66ebed9b2
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<!--<!DOCTYPE configuration SYSTEM "config.dtd">-->
|
||||
<!--
|
||||
this file contains templates which allow an user easy
|
||||
configuration of Fop. Actually normally you don't need this configuration
|
||||
file, but if you need to change configuration, you should
|
||||
always use this file and *not* config.xml.
|
||||
Usage: java org.apache.fop.apps.Fop -c userconfig.xml -fo fo-file -pdf pdf-file
|
||||
-->
|
||||
|
||||
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
baseDir: normally the base directory is the directory where the fo file is
|
||||
located. if you want to specify your own, uncomment this entry.
|
||||
This value can also be a URL. Actually, the value is converted to
|
||||
a URL.
|
||||
-->
|
||||
<!--
|
||||
<entry>
|
||||
<key>baseDir</key>
|
||||
<value></value>
|
||||
</entry>
|
||||
-->
|
||||
|
||||
<!--
|
||||
fontBaseDir: Similar to baseDir, except that this value is used for fonts. If
|
||||
it isn't specified, the value from baseDir is used.
|
||||
-->
|
||||
<!--
|
||||
<entry>
|
||||
<key>fontBaseDir</key>
|
||||
<value></value>
|
||||
</entry>
|
||||
-->
|
||||
|
||||
<!--
|
||||
************************************************************************
|
||||
HYPHENATION
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<!--
|
||||
hyphenation directory
|
||||
if you want to specify your own directory with hyphenation pattern
|
||||
then uncomment the next entry and add the directory name
|
||||
-->
|
||||
|
||||
<!--
|
||||
<entry>
|
||||
<key>hyphenation-dir</key>
|
||||
<value>/java/xml-fop/hyph</value>
|
||||
</entry>
|
||||
-->
|
||||
|
||||
<!--
|
||||
************************************************************************
|
||||
Add fonts here
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<fonts>
|
||||
<!-- Example Japanese fonts
|
||||
<font metrics-file="msgothic.xml" embed-file="D:\winnt\font\msgothic.ttc" kerning="yes">
|
||||
<font-triplet name="Gothic" style="normal" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="normal" weight="bold"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="bold"/>
|
||||
</font>
|
||||
<font metrics-file="msmincho.xml" embed-file="Cyberbit.ttf" kerning="yes">
|
||||
<font-triplet name="Mincho" style="normal" weight="normal"/>
|
||||
<font-triplet name="Mincho" style="normal" weight="bold"/>
|
||||
<font-triplet name="Mincho" style="italic" weight="normal"/>
|
||||
<font-triplet name="Mincho" style="italic" weight="bold"/>
|
||||
</font>
|
||||
-->
|
||||
|
||||
<font metrics-file="msmincho.xml" kerning="yes" embed-file="msmincho.ttc">
|
||||
<font-triplet name="MS-Mincho" style="normal" weight="normal"/>
|
||||
<font-triplet name="MS-Mincho" style="normal" weight="bold"/>
|
||||
<font-triplet name="MS-Mincho" style="italic" weight="normal"/>
|
||||
<font-triplet name="MS-Mincho" style="italic" weight="bold"/>
|
||||
<font-triplet name="MSMincho" style="normal" weight="normal"/>
|
||||
<font-triplet name="MSMincho" style="normal" weight="bold"/>
|
||||
<font-triplet name="MSMincho" style="italic" weight="normal"/>
|
||||
<font-triplet name="MSMincho" style="italic" weight="bold"/>
|
||||
<font-triplet name="Mincho" style="normal" weight="normal"/>
|
||||
<font-triplet name="Mincho" style="normal" weight="bold"/>
|
||||
<font-triplet name="Mincho" style="italic" weight="normal"/>
|
||||
<font-triplet name="Mincho" style="italic" weight="bold"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="normal" weight="normal"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="normal" weight="bold"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="italic" weight="normal"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="italic" weight="bold"/>
|
||||
<font-triplet name="serif" style="normal" weight="normal"/>
|
||||
<font-triplet name="serif" style="normal" weight="bold"/>
|
||||
<font-triplet name="serif" style="italic" weight="normal"/>
|
||||
<font-triplet name="serif" style="italic" weight="bold"/>
|
||||
</font>
|
||||
|
||||
<font metrics-file="msgothic.xml" kerning="yes" embed-file="msgothic.ttc">
|
||||
<font-triplet name="MS-Gothic" style="normal" weight="normal"/>
|
||||
<font-triplet name="MS-Gothic" style="normal" weight="bold"/>
|
||||
<font-triplet name="MS-Gothic" style="italic" weight="normal"/>
|
||||
<font-triplet name="MS-Gothic" style="italic" weight="bold"/>
|
||||
<font-triplet name="MSGothic" style="normal" weight="normal"/>
|
||||
<font-triplet name="MSGothic" style="normal" weight="bold"/>
|
||||
<font-triplet name="MSGothic" style="italic" weight="normal"/>
|
||||
<font-triplet name="MSGothic" style="italic" weight="bold"/>
|
||||
<font-triplet name="Gothic" style="normal" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="normal" weight="bold"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="normal"/>
|
||||
<font-triplet name="Gothic" style="italic" weight="bold"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="normal" weight="normal"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="normal" weight="bold"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="italic" weight="normal"/>
|
||||
<font-triplet name="‚l‚r–¾’©" style="italic" weight="bold"/>
|
||||
<font-triplet name="sans-serif" style="normal" weight="normal"/>
|
||||
<font-triplet name="sans-serif" style="normal" weight="bold"/>
|
||||
<font-triplet name="sans-serif" style="italic" weight="normal"/>
|
||||
<font-triplet name="sans-serif" style="italic" weight="bold"/>
|
||||
</font>
|
||||
|
||||
</fonts>
|
||||
|
||||
</configuration>
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 9.1 KiB |
|
@ -0,0 +1,429 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="354.331"
|
||||
height="336.614"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
|
||||
style="font-size:12;"
|
||||
id="g659">
|
||||
<rect
|
||||
width="212.257"
|
||||
height="57.2441"
|
||||
x="17.9576"
|
||||
y="100.132"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<rect
|
||||
width="325.86"
|
||||
height="63.6537"
|
||||
x="17.4083"
|
||||
y="15.194"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="325.86"
|
||||
height="63.6537"
|
||||
x="13.6713"
|
||||
y="12.4966"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
<g
|
||||
transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<text
|
||||
x="170.824753"
|
||||
y="58.402939"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="170.824997"
|
||||
y="58.402901"
|
||||
id="tspan360">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="178.076340"
|
||||
y="364.281433"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="178.076004"
|
||||
y="364.281006"
|
||||
id="tspan421">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="68.605331"
|
||||
y="138.524582"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="68.605301"
|
||||
y="138.524994"
|
||||
id="tspan384">
|
||||
SessionFactory</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="67.0014"
|
||||
height="101.35"
|
||||
x="196.927"
|
||||
y="89.2389"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect387" />
|
||||
<rect
|
||||
width="67.0014"
|
||||
height="101.35"
|
||||
x="194.633"
|
||||
y="86.4389"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect388" />
|
||||
<text
|
||||
x="249.108841"
|
||||
y="173.885559"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text389">
|
||||
<tspan
|
||||
x="249.108994"
|
||||
y="173.886002"
|
||||
id="tspan392">
|
||||
Session</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="73.0355"
|
||||
height="101.35"
|
||||
x="270.995"
|
||||
y="90.0018"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect395" />
|
||||
<rect
|
||||
width="73.0355"
|
||||
height="101.35"
|
||||
x="267.869"
|
||||
y="87.2018"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect396" />
|
||||
<text
|
||||
x="328.593658"
|
||||
y="174.715622"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text397">
|
||||
<tspan
|
||||
x="328.593994"
|
||||
y="174.716003"
|
||||
id="tspan563">
|
||||
Transaction</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
|
||||
style="font-size:12;"
|
||||
id="g565">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect566" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect567" />
|
||||
</g>
|
||||
<text
|
||||
x="25.592752"
|
||||
y="204.497803"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text568">
|
||||
<tspan
|
||||
x="25.592800"
|
||||
y="204.498001"
|
||||
id="tspan662">
|
||||
TransactionFactory</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
|
||||
style="font-size:12;"
|
||||
id="g573">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect574" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect575" />
|
||||
</g>
|
||||
<text
|
||||
x="134.030670"
|
||||
y="205.532791"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text576">
|
||||
<tspan
|
||||
x="134.031006"
|
||||
y="205.533005"
|
||||
id="tspan664">
|
||||
ConnectionProvider</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
|
||||
style="font-size:12;"
|
||||
id="g587">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect588" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect589" />
|
||||
</g>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="25.6196"
|
||||
y="206.028"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect594" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="24.4229"
|
||||
y="204.135"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect595" />
|
||||
<text
|
||||
x="85.575645"
|
||||
y="282.300354"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text596">
|
||||
<tspan
|
||||
x="85.575600"
|
||||
y="282.299988"
|
||||
id="tspan607">
|
||||
JNDI</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="236.937"
|
||||
y="206.791"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect610" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="235.741"
|
||||
y="204.898"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect611" />
|
||||
<text
|
||||
x="342.093201"
|
||||
y="283.226410"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text612">
|
||||
<tspan
|
||||
x="342.092987"
|
||||
y="283.226013"
|
||||
id="tspan621">
|
||||
JTA</tspan>
|
||||
</text>
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="130.134"
|
||||
y="206.791"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect616" />
|
||||
<rect
|
||||
width="90.951"
|
||||
height="44.4829"
|
||||
x="128.937"
|
||||
y="204.898"
|
||||
style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect617" />
|
||||
<text
|
||||
x="212.445343"
|
||||
y="283.226410"
|
||||
transform="scale(0.823795,0.823795)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text618">
|
||||
<tspan
|
||||
x="212.445007"
|
||||
y="283.226013"
|
||||
id="tspan623">
|
||||
JDBC</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
|
||||
style="font-size:12;"
|
||||
id="g637">
|
||||
<g
|
||||
transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="33.749969"
|
||||
y="50.589706"
|
||||
style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="33.750000"
|
||||
y="50.589699"
|
||||
id="tspan635">
|
||||
Transient Objects</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
|
||||
style="font-size:12;"
|
||||
id="g644">
|
||||
<g
|
||||
transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
|
||||
id="g364">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect365" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect366" />
|
||||
</g>
|
||||
<text
|
||||
x="277.123230"
|
||||
y="85.155571"
|
||||
style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text367">
|
||||
<tspan
|
||||
x="277.122986"
|
||||
y="85.155602"
|
||||
id="tspan631">
|
||||
Persistent</tspan>
|
||||
<tspan
|
||||
x="277.122986"
|
||||
y="96.155602"
|
||||
id="tspan633">
|
||||
Objects</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 6.6 KiB |
|
@ -0,0 +1,334 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="318.898"
|
||||
height="248.031"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<rect
|
||||
width="291.837"
|
||||
height="57.0074"
|
||||
x="17.3169"
|
||||
y="18.646"
|
||||
style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="291.837"
|
||||
height="57.0074"
|
||||
x="13.9703"
|
||||
y="16.2302"
|
||||
style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
<g
|
||||
transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g161">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
|
||||
style="font-size:12;"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="302.277679"
|
||||
y="65.943230"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="302.277954"
|
||||
y="65.943184"
|
||||
id="tspan360">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="36.235924"
|
||||
y="63.796055"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="36.235950"
|
||||
y="63.796051"
|
||||
id="tspan427">
|
||||
Transient Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="180.416245"
|
||||
y="290.543701"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="180.415939"
|
||||
y="290.543549"
|
||||
id="tspan421">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="25.037701"
|
||||
y="179.154755"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="25.037655"
|
||||
y="179.154648"
|
||||
id="tspan384">
|
||||
SessionFactory</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g386">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect387" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect388" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
|
||||
style="font-size:12;"
|
||||
id="g364">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect365" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect366" />
|
||||
</g>
|
||||
<text
|
||||
x="202.746506"
|
||||
y="102.992203"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
|
||||
id="text367">
|
||||
<tspan
|
||||
x="202.746948"
|
||||
y="102.992249"
|
||||
id="tspan423">
|
||||
Persistent</tspan>
|
||||
<tspan
|
||||
x="202.746948"
|
||||
y="116.992355"
|
||||
id="tspan425">
|
||||
Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="174.458496"
|
||||
y="180.080795"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text389">
|
||||
<tspan
|
||||
x="174.458618"
|
||||
y="180.080338"
|
||||
id="tspan392">
|
||||
Session</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g394">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect395" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect396" />
|
||||
</g>
|
||||
<text
|
||||
x="260.413269"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text397">
|
||||
<tspan
|
||||
x="260.412964"
|
||||
y="179.154343"
|
||||
id="tspan400">
|
||||
JDBC</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g405">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect406" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect407" />
|
||||
</g>
|
||||
<text
|
||||
x="320.606903"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text408">
|
||||
<tspan
|
||||
x="320.606964"
|
||||
y="179.154343"
|
||||
id="tspan417">
|
||||
JNDI</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
|
||||
style="font-size:12;"
|
||||
id="g411">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect412" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect413" />
|
||||
</g>
|
||||
<text
|
||||
x="377.096313"
|
||||
y="179.154739"
|
||||
transform="scale(0.73778,0.73778)"
|
||||
style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text414">
|
||||
<tspan
|
||||
x="377.096008"
|
||||
y="179.154999"
|
||||
id="tspan145">
|
||||
JTA</tspan>
|
||||
</text>
|
||||
</svg>
|
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 843 B |
After Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1,250 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
|
||||
[
|
||||
<!ATTLIST svg
|
||||
xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
|
||||
]>
|
||||
<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="248.031"
|
||||
height="248.031"
|
||||
id="svg1">
|
||||
<defs
|
||||
id="defs3">
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop129" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
id="linearGradient130"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
<radialGradient
|
||||
cx="0.5"
|
||||
cy="0.5"
|
||||
fx="0.5"
|
||||
fy="0.5"
|
||||
r="0.5"
|
||||
id="radialGradient131"
|
||||
xlink:href="#linearGradient127"
|
||||
gradientUnits="objectBoundingBox"
|
||||
spreadMethod="pad" />
|
||||
</defs>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
|
||||
style="font-size:12;"
|
||||
id="g158">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="17.3527"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect136" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="15.3883"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect126" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
|
||||
style="font-size:12;"
|
||||
id="g161">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="16.6979"
|
||||
y="99.2053"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect137" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="118.523"
|
||||
x="13.4238"
|
||||
y="95.9309"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect132" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
|
||||
style="font-size:12;"
|
||||
id="g164">
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="16.6979"
|
||||
y="222.966"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect138" />
|
||||
<rect
|
||||
width="285.502"
|
||||
height="77.2688"
|
||||
x="14.7335"
|
||||
y="221.002"
|
||||
transform="translate(-1.30962,-1.30992)"
|
||||
style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect133" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
|
||||
style="font-size:12;"
|
||||
id="g167">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect134" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect135" />
|
||||
</g>
|
||||
<text
|
||||
x="105.392174"
|
||||
y="56.568123"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text183">
|
||||
<tspan
|
||||
x="105.392273"
|
||||
y="56.568146"
|
||||
id="tspan186">
|
||||
Application</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="81.820183"
|
||||
y="103.149330"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text188">
|
||||
<tspan
|
||||
x="81.820213"
|
||||
y="103.149727"
|
||||
id="tspan206">
|
||||
Persistent Objects</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="111.548180"
|
||||
y="278.927887"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text197">
|
||||
<tspan
|
||||
x="111.547874"
|
||||
y="278.927551"
|
||||
id="tspan200">
|
||||
Database</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="94.436180"
|
||||
y="153.805740"
|
||||
transform="scale(0.771934,0.771934)"
|
||||
style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
|
||||
id="text216">
|
||||
<tspan
|
||||
x="94.436180"
|
||||
y="153.805740"
|
||||
id="tspan221">
|
||||
HIBERNATE</tspan>
|
||||
</text>
|
||||
<g
|
||||
transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
|
||||
style="font-size:12;"
|
||||
id="g254">
|
||||
<g
|
||||
transform="translate(4.58374,2.61928)"
|
||||
id="g176">
|
||||
<g
|
||||
transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
|
||||
id="g170">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect171" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect172" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
|
||||
id="g173">
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="61.8805"
|
||||
y="68.4288"
|
||||
style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect174" />
|
||||
<rect
|
||||
width="199.065"
|
||||
height="61.5532"
|
||||
x="59.2613"
|
||||
y="65.8095"
|
||||
style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
|
||||
id="rect175" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
x="47.259438"
|
||||
y="182.367538"
|
||||
style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
|
||||
id="text191">
|
||||
<tspan
|
||||
x="47.259399"
|
||||
y="182.367996"
|
||||
id="tspan212">
|
||||
hibernate.</tspan>
|
||||
<tspan
|
||||
x="47.259399"
|
||||
y="194.367996"
|
||||
id="tspan214">
|
||||
properties</tspan>
|
||||
</text>
|
||||
<text
|
||||
x="198.523010"
|
||||
y="188.260941"
|
||||
style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
|
||||
id="text194">
|
||||
<tspan
|
||||
id="tspan195">
|
||||
XML Mapping</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
|
@ -0,0 +1,246 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
|
||||
"../support/docbook-dtd/docbookx.dtd"
|
||||
[
|
||||
<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
|
||||
<!ENTITY architecture SYSTEM "modules/architecture.xml">
|
||||
<!ENTITY configuration SYSTEM "modules/configuration.xml">
|
||||
<!ENTITY persistent-classes SYSTEM "modules/persistent_classes.xml">
|
||||
<!ENTITY basic-mapping SYSTEM "modules/basic_mapping.xml">
|
||||
<!ENTITY collection-mapping SYSTEM "modules/collection_mapping.xml">
|
||||
<!ENTITY association-mapping SYSTEM "modules/association_mapping.xml">
|
||||
<!ENTITY component-mapping SYSTEM "modules/component_mapping.xml">
|
||||
<!ENTITY inheritance-mapping SYSTEM "modules/inheritance_mapping.xml">
|
||||
<!ENTITY session-api SYSTEM "modules/session_api.xml">
|
||||
<!ENTITY transactions SYSTEM "modules/transactions.xml">
|
||||
<!ENTITY events SYSTEM "modules/events.xml">
|
||||
<!ENTITY batch SYSTEM "modules/batch.xml">
|
||||
<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
|
||||
<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
|
||||
<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
|
||||
<!ENTITY filters SYSTEM "modules/filters.xml">
|
||||
<!ENTITY xml SYSTEM "modules/xml.xml">
|
||||
<!ENTITY performance SYSTEM "modules/performance.xml">
|
||||
<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
|
||||
<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
|
||||
<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
|
||||
<!ENTITY example-mappings SYSTEM "modules/example_mappings.xml">
|
||||
<!ENTITY best-practices SYSTEM "modules/best_practices.xml">
|
||||
]>
|
||||
|
||||
<book lang="ja">
|
||||
|
||||
<bookinfo>
|
||||
<title>HIBERNATE - Relational Persistence for Idiomatic Java</title>
|
||||
<subtitle>Hibernate Reference Documentation</subtitle>
|
||||
<releaseinfo>3.1.2</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<toc/>
|
||||
|
||||
<preface id="preface" revision="2">
|
||||
<title>前書き</title>
|
||||
|
||||
<para>
|
||||
WARNING! This is a translated version of the English Hibernate reference
|
||||
documentation. The translated version might not be up to date! However, the
|
||||
differences should only be very minor. Consult the English reference
|
||||
documentation if you are missing information or encounter a translation
|
||||
error. If you like to contribute to a particular translation, contact us
|
||||
on the Hibernate developer mailing list.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Translator(s): Chikara Honma, Yusuke Hiroto;
|
||||
</para>
|
||||
|
||||
<para>
|
||||
今日の企業環境において、オブジェクト指向ソフトウェアとリレーショナルデータベースに関わる作業は
|
||||
煩雑で膨大な時間を必要とします。
|
||||
HibernateはJava環境のオブジェクト/リレーショナルマッピングツールです。
|
||||
オブジェクト/リレーショナルマッピング(ORM)とは、
|
||||
オブジェクトモデルからSQLベーススキーマのリレーショナルデータモデルへと、
|
||||
データ表現をマッピングする(対応付ける)技術のことです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HibernateはJavaクラスからデータベーステーブルへ(そしてJavaデータ型からSQLデータ型へ)
|
||||
のマッピングを処理するだけではなく、データのクエリと復元の仕組みをも提供します。
|
||||
このおかげでSQLとJDBCを使った手作業でのデータ処理に費やされていた開発時間を大幅に削減できます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernateの最終目標は、データの永続化に関わる一般的なプログラミング作業の95%から開発者を解放することです。
|
||||
Hibernateはビジネスロジックの実装にストアドプロシージャを使う
|
||||
データ中心アプリケーションに対してのベストソリューションであるに留まりません。
|
||||
オブジェクト指向ドメインモデルとJavaベースの中間層でのビジネスロジックに対して最も役に立ちます。
|
||||
しかしHibernateはベンダ固有のSQLコードを削減またはカプセル化したり、
|
||||
表形式からオブジェクトのグラフへとリザルトセットを変換するなどの、
|
||||
一般的なタスクにも役立つでしょう。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernateやオブジェクト/リレーショナルマッピング、
|
||||
さらにはJavaが初めての方は、以下のステップに従ってください:
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="tutorial"/> を読んでください。
|
||||
段階的に解説していきます。
|
||||
<xref linkend="tutorial"/> を読んでください。
|
||||
段階的に解説していきます。
|
||||
チュートリアルのソースコードはディストリビューションの
|
||||
<literal>doc/reference/tutorial</literal> ディレクトリに含まれています。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<xref linkend="architecture"/> を読んで、Hibernateが利用可能な環境を理解してください。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernateディストリビューションの <literal>eg/</literal> ディレクトリを見てください。
|
||||
簡単なスタンドアローンのアプリケーションがあります。
|
||||
JDBCドライバを <literal>lib/</literal> ディレクトリにコピーして、
|
||||
自分のデータベースに合う正しい値を指定するように <literal>etc/hibernate.properties</literal>
|
||||
を編集してください。
|
||||
ディストリビューションディレクトリから、コマンドプロンプトで
|
||||
<literal>ant eg</literal> とタイプしてください(Antを使います)。
|
||||
またWindows環境では <literal>build eg</literal> とタイプしてください。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
このリファレンスドキュメントを第一の情報源として利用してください。
|
||||
アプリケーション設計についてのさらなる情報や段階的なチュートリアルを探しているなら、
|
||||
<emphasis>Hibernate in Action</emphasis>(http://www.manning.com/bauer)
|
||||
をおすすめします。
|
||||
またhttp://caveatemptor.hibernate.orgから
|
||||
Hibernate in Actionの例題のアプリケーションをダウンロードできます。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
FAQはHibernateウェブサイトにあります。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
サードパーティのデモ、例、チュートリアルはHibernateウェブサイトにリンクがあります。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernateウェブサイトのコミュニティエリアは、デザインパターンやさまざまな統合ソリューション
|
||||
(Tomcat, JBoss AS, Struts, EJB, 等)についてのよい情報源です。
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>
|
||||
質問があればHibernateウェブサイトのユーザフォーラムを活用してください。
|
||||
またバグレポートとフィーチャリクエストのためJIRA問題追跡システムを用意しています。
|
||||
Hibernateの開発に興味があれば、開発者メーリングリストに参加してください。
|
||||
このドキュメントをあなた達の言語へ翻訳したい場合は、
|
||||
開発者メーリングリストで私たちにコンタクトを取ってください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
商用開発のサポート、製品のサポート、HibernateのトレーニングはJBoss Inc.が提供しています
|
||||
(http://www.hibernate.org/SupportTraining/を見てください)。
|
||||
HibernateはProfessional Open Sourceプロジェクト、
|
||||
そしてJBoss Enterprise Middleware System(JEMS)プロダクトスイートのクリティカルコンポーネントです。
|
||||
</para>
|
||||
|
||||
<sect1 id="preface-s1" revision="-1">
|
||||
|
||||
<title>日本語訳について</title>
|
||||
|
||||
<para id="preface-s1-p1" revision="-1">
|
||||
この日本語版Hibernate Reference Document(以下、日本語版)は、
|
||||
Hibernateプロジェクトの翻訳プロセスに基づいて作成されています。
|
||||
日本語版ならびに原文はLGPLライセンスに準じます。
|
||||
</para>
|
||||
|
||||
<para id="preface-s1-p2" revision="-1">
|
||||
日本語版の利用によって第三者が被るあらゆる不利益に対して、
|
||||
原著者、翻訳者ならびにその組織は一切の保証をいたしかねます。
|
||||
日本語版は誤りを含む可能性があることを認識した上でご利用ください。
|
||||
内容の正確な意味を把握するためには、原文を読むことをおすすめします。
|
||||
また、もし日本語版に誤りを見つけられた場合は、翻訳者にご連絡いただければ幸いです。
|
||||
ただし内容に関してのお問い合わせには応じかねますので、ご了承ください。
|
||||
</para>
|
||||
|
||||
<sect2 id="preface-s1-1" revision="-1">
|
||||
|
||||
<title>日本語版翻訳者について</title>
|
||||
|
||||
<para id="preface-s1-1-p4" revision="-1">
|
||||
日本語版バージョン3.1.2の翻訳は株式会社エクサ
|
||||
(<ulink url="http://www.exa-corp.co.jp">ホームページはこちら</ulink>)
|
||||
の以下のメンバーで行いました。
|
||||
本間力(6,18,19,21,22,23章担当)、
|
||||
広戸裕介(前書き,2,5,13,14,24,25章担当)、
|
||||
武市正人(7,8,9,10章担当)、
|
||||
那須秀男(12,16,17章担当)、
|
||||
井関知文(1,3,11章担当)、
|
||||
飯田浩司(4,15章担当)、
|
||||
平間健一(20章担当)、
|
||||
森龍二(レビュー担当)。
|
||||
なお誤訳等のご指摘は本間、広戸までお願いいたします。
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/mailaddr.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/mailaddr.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
</preface>
|
||||
|
||||
&tutorial;
|
||||
|
||||
&architecture;
|
||||
|
||||
&configuration;
|
||||
|
||||
&persistent-classes;
|
||||
|
||||
&basic-mapping;
|
||||
&collection-mapping;
|
||||
&association-mapping;
|
||||
&component-mapping;
|
||||
&inheritance-mapping;
|
||||
|
||||
&session-api;
|
||||
&transactions;
|
||||
&events;
|
||||
&batch;
|
||||
|
||||
&query-hql;
|
||||
&query-criteria;
|
||||
&query-sql;
|
||||
&filters;
|
||||
&xml;
|
||||
|
||||
&performance;
|
||||
|
||||
&toolset-guide;
|
||||
|
||||
&example-parentchild;
|
||||
&example-weblog;
|
||||
&example-mappings;
|
||||
|
||||
&best-practices;
|
||||
|
||||
</book>
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="architecture">
|
||||
|
||||
<title>アーキテクチャ</title>
|
||||
|
||||
<sect1 id="architecture-overview" revision="1">
|
||||
<title>概観</title>
|
||||
|
||||
<para>
|
||||
Hibernateアーキテクチャの(非常に)高いレベルからのビュー:
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/overview.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/overview.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
この図はHibernateが、アプリケーションに対して永続化サービス
|
||||
(と永続オブジェクト)を提供するために、データベースと設定データを使うことを
|
||||
示しています。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
|
||||
あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
|
||||
ここでは、2つの極端な例をお見せします。
|
||||
「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
|
||||
アプリケーション自身がトランザクションを管理します。
|
||||
この方法は、Hibernate APIの最小限のサブセットを使います:
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/lite.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/lite.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
|
||||
取り払って抽象化し、その詳細の面倒をHibernateに見させます。
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/full_cream.svg" format="SVG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/full_cream.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
以下は、上の図に含まれるオブジェクトの定義です:
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
1つのデータベースに対するコンパイルされたマッピングの
|
||||
スレッドセーフな(更新不能の)キャッシュ。
|
||||
<literal>Session</literal> のファクトリであり、
|
||||
<literal>ConnectionProvider</literal> のクライアント。
|
||||
オプションとして、プロセスまたはクラスタレベルにおいて、
|
||||
トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Session (<literal>org.hibernate.Session</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
アプリケーションと永続ストアとの対話を表す、
|
||||
シングル・スレッドで短命のオブジェクト。
|
||||
JDBCコネクションをラップします。
|
||||
<literal>Transaction</literal> のファクトリです。
|
||||
永続オブジェクトの必須の(一次)キャッシュを保持します。
|
||||
このキャッシュはオブジェクトグラフをナビゲーションする時や、
|
||||
識別子でオブジェクトを検索する時に使われます。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Persistent objects と Collections</term>
|
||||
<listitem>
|
||||
<para>
|
||||
永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
|
||||
これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
|
||||
その時点での(ただ1つの) <literal>Session</literal> と関連していることです。
|
||||
<literal>Session</literal> がクローズされるとすぐに、
|
||||
それらは切り離されて他のアプリケーション層から自由に使うことができます。
|
||||
(例えばデータ・トランスファ・オブジェクトとして、
|
||||
プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Transient と detached な objects と Collections</term>
|
||||
<listitem>
|
||||
<para>
|
||||
現時点では <literal>Session</literal> と関連していない、
|
||||
永続クラスのインスタンス。
|
||||
すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
|
||||
クローズされた <literal>Session</literal> でインスタンス化されたかのどちらかです。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
|
||||
シングル・スレッドで短命なオブジェクト。
|
||||
下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
|
||||
<literal>Session</literal> は、時には
|
||||
いくつかの <literal>Transaction</literal> をまたがるかもしれません。
|
||||
しかし、下の層のAPIを使うにせよ、 <literal>Transaction</literal> を使うにせよ、
|
||||
トランザクション境界を設定することは、決してオプションではありません!。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(オプション)JDBCコネクション(とそのプール)のファクトリ。
|
||||
下の層に位置する <literal>Datasource</literal> や
|
||||
<literal>DriverManager</literal> からアプリケーションを抽象化します。
|
||||
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
|
||||
<listitem>
|
||||
<para>
|
||||
(オプション) <literal>Transaction</literal> インスタンスのファクトリ。
|
||||
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><emphasis>Extension Interfaces</emphasis></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernateは、永続層の振る舞いをカスタマイズするために、
|
||||
多くのオプション拡張インタフェースを用意しています。
|
||||
詳細はAPIドキュメントを参照してください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
|
||||
<literal>Transaction</literal> や <literal>TransactionFactory</literal> や
|
||||
<literal>ConnectionProvider</literal> をバイパスします。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-states" revision="1">
|
||||
<title>インスタンスの状態</title>
|
||||
<para>
|
||||
永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
|
||||
それは、 <emphasis>永続コンテキスト</emphasis> によって決まります。
|
||||
Hibernateの <literal>Session</literal> オブジェクトが、永続コンテキストになります。
|
||||
</para>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>transient</term>
|
||||
<listitem>
|
||||
<para>
|
||||
この状態のインスタンスは、現在もそして過去においても、
|
||||
永続コンテキストに関連づいていません。また、永続ID(主キーの値)を
|
||||
持っていません。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>persistent</term>
|
||||
<listitem>
|
||||
<para>
|
||||
この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
|
||||
また、永続ID(主キーの値)を持ち、
|
||||
たいていはデータベースに対応する行を持っているでしょう。
|
||||
個々の永続コンテキストのなかでは、永続IDが
|
||||
JavaのID(オブジェクトのメモリ上の位置)と同じであることを
|
||||
Hibernateが <emphasis>保証</emphasis> します。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>detached</term>
|
||||
<listitem>
|
||||
<para>
|
||||
この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
|
||||
そのコンテキストがクローズされたか、あるいは、
|
||||
他のプロセスにそのインスタンスがシリアライズされたかです。
|
||||
このインスタンスは、永続IDを持ち、たいていはデータベースに
|
||||
対応する行を持っているでしょう。分離インスタンスに対しては、
|
||||
永続IDとJavaのIDとの関連は、Hibernateが保証しません。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-jmx" revision="1">
|
||||
<title>JMXとの統合</title>
|
||||
|
||||
<para>
|
||||
JMXはJavaコンポーネント管理のJ2EE標準です。
|
||||
JMX標準サービスを通して、Hibernateは管理されます。
|
||||
ディストリビューションの中に <literal>org.hibernate.jmx.HibernateService</literal> という
|
||||
MBean実装を用意しています。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
|
||||
JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
|
||||
JMXを使ってデプロイすると、次のメリットが得られます。
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>セッション管理:</emphasis> Hibernateの <literal>Session</literal> のライフサイクルは、
|
||||
自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
|
||||
<literal>Session</literal> をオープンしたり、クローズしたりする必要がないことを意味します。
|
||||
これは、JBoss EJB インターセプタの仕事になります。
|
||||
また、コードのどこでトランザクション境界を設定するかについて、
|
||||
もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
|
||||
オプションのHibernateの <literal>Transaction</literal> を使用してください。)
|
||||
<literal>Session</literal> にアクセスするためには、 <literal>HibernateContext</literal> を
|
||||
コールしてください。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>HAR デプロイ:</emphasis> 通常、(EAR または SAR ファイルにある)JBoss サービス
|
||||
デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
|
||||
それは、Hibernateの <literal>SessionFactory</literal> の全ての一般的な設定オプションを
|
||||
サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
|
||||
名前を挙げる必要があります。
|
||||
もし、オプションのHARデプロイメントを使うことを決めたなら、
|
||||
JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
|
||||
参考にしてください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
|
||||
<xref linkend="configuration-optional-statistics"/> を見てください。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-jca" revision="1">
|
||||
<title>JCA サポート</title>
|
||||
<para>
|
||||
Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
|
||||
Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="architecture-current-session" revision="1">
|
||||
<title>コンテキスト上のセッション</title>
|
||||
<para>
|
||||
Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
|
||||
「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
|
||||
しかし、ふつう、アプリケーションごとにコンテキストを構成するものの定義は異なります。
|
||||
しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
|
||||
バージョン3.0より前の Hibernate では、自作の <literal>ThreadLocal</literal> ベースの「コンテキスト上のセッション」を
|
||||
利用するか、 <literal>HibernateUtil</literal> のようなヘルパークラスを利用するか、
|
||||
proxy/interception ベースの「コンテキスト上のセッション」を提供する
|
||||
(Spring や Pico のような)サードパーティのフレームワークを利用するかのどれかでした。
|
||||
</para>
|
||||
<para>
|
||||
バージョン 3.0.1 から、Hibernate には <literal>SessionFactory.getCurrentSession()</literal> が
|
||||
加わりました。 これは、 <literal>JTA</literal> トランザクションの使用を前提にしています。
|
||||
<literal>JTA</literal> トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
|
||||
Hibernate チームは、次のことを主張します。
|
||||
巨大なスタンドアロンの <literal>JTA TransactionManager</literal> 実装が成熟したら、
|
||||
<literal>J2EE</literal> コンテナ上にデプロイされるかどうかにかかわらず、
|
||||
ほとんどの(すべてとは言わないが)アプリケーションが、
|
||||
<literal>JTA</literal> トランザクション管理を使用すべきであると。
|
||||
この考えに基づくと、 <literal>JTA</literal> ベースの「コンテキスト上のセッション」を
|
||||
使うしかないでしょう。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
しかし、バージョン 3.1 からは、 <literal>SessionFactory.getCurrentSession()</literal> の後の処理が、
|
||||
プラガブルになりました。
|
||||
これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
|
||||
新しい拡張インタフェース ( <literal>org.hibernate.context.CurrentSessionContext</literal> ) と
|
||||
新しい構成パラメータ ( <literal>hibernate.current_session_context_class</literal> ) が追加されました。
|
||||
</para>
|
||||
<para>
|
||||
<literal>org.hibernate.context.CurrentSessionContext</literal> インタフェースの規約についての
|
||||
詳細な内容は Javadoc を参照してください。
|
||||
それには、 <literal>currentSession()</literal> という1つのメソッドが定義されており、
|
||||
その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
|
||||
そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>org.hibernate.context.JTASessionContext</literal> -
|
||||
<literal>JTA</literal> トランザクションによって、現在のセッションが追跡され、
|
||||
スコープを決められます。この処理は、古い JTAだけのアプローチとまったく同じです。
|
||||
詳細は、Javadoc を参照してください。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> -
|
||||
スレッドの実行によって、現在のセッションが追跡されます。
|
||||
詳細は、Javadoc を参照してください。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
この2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
|
||||
また、 <emphasis>リクエストごとのセッション</emphasis> として知られており、使われています。
|
||||
Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
|
||||
もし、プログラムによるトランザクション境界設定(例:純粋な J2SE や JTA/UserTransaction/BMT を使用する場合)
|
||||
を使いたいなら、下位にあるトランザクションシステムを隠蔽するために、
|
||||
Hibernate の <literal>Transaction</literal> を使った方が良いです。
|
||||
もし、CMT をサポートする EJB コンテナーで動作させるつもりならば、トランザクション境界は、
|
||||
宣言的に定義でき、トランザクションやセッションの境界設定に関するどのような操作も必要となりません。
|
||||
より詳細な情報やコードの例は、 <xref linkend="transactions"/> を参照してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>hibernate.current_session_context_class</literal> 構成パラメータは、
|
||||
<literal>org.hibernate.context.CurrentSessionContext</literal> のどの実装を使うかを指定します。
|
||||
下位互換性のため、この構成パラメータが設定されずに
|
||||
<literal>org.hibernate.transaction.TransactionManagerLookup</literal> が設定されていた場合は、
|
||||
<literal>org.hibernate.context.JTASessionContext</literal> を使います。
|
||||
通常、このパラメータの値には、2つのすぐに使える実装のうち、使用する方の実装クラスの名前を指定しますが、
|
||||
"jta" と "thread" というそれぞれの省略名も用意されています。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,620 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="associations">
|
||||
|
||||
<title>関連マッピング</title>
|
||||
|
||||
<sect1 id="assoc-intro" revision="1">
|
||||
<title>イントロダクション</title>
|
||||
|
||||
<para>
|
||||
関連マッピングはしばしば理解が最も難しいものになります。
|
||||
この章では、基本的な一つ一つのケースについて述べます。
|
||||
単方向のマッピングから始め、それから双方向のケースについて考えていきます。
|
||||
例として、<literal>Person</literal> と <literal>Address</literal> を用います。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
関連は、結合テーブルを入れるかかどうかと、
|
||||
多重度によって分類することにします。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
すべての例でnot nullの外部キーを使用します。
|
||||
これはHibernateの要件ではありません。
|
||||
not null制約を外したとしても、マッピングは問題なく動作します。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-unidirectional" revision="1">
|
||||
<title>単方向関連</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-m21">
|
||||
<title>多対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>単方向多対一関連</emphasis> は単方向関連の中で最も一般的なものです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-121">
|
||||
<title>一対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>外部キーの単方向一対一関連</emphasis> はほとんど同じものです。
|
||||
唯一違うのは、カラムのユニークな制約です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
unique="true"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>主キーの単方向一対一関連</emphasis> は通常、特別なIDジェネレータを使います。
|
||||
(この例では関連の方向が逆になっていることに注意してください)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="personId">
|
||||
<generator class="foreign">
|
||||
<param name="property">person</param>
|
||||
</generator>
|
||||
</id>
|
||||
<one-to-one name="person" constrained="true"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( personId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-12m">
|
||||
<title>一対多</title>
|
||||
|
||||
<para>
|
||||
<emphasis>外部キーの単方向一対多関連</emphasis> はとても特殊なケースで、
|
||||
あまり推奨されていません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses">
|
||||
<key column="personId"
|
||||
not-null="true"/>
|
||||
<one-to-many class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key, personId bigint not null )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
このような関連のために結合テーブルを使うことをお薦めします。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-unidirectional-join" revision="1">
|
||||
<title>結合テーブルを使った単方向関連</title>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-12m">
|
||||
<title>一対多</title>
|
||||
|
||||
<para>
|
||||
<emphasis>結合テーブルを使った単方向一対多関連</emphasis>
|
||||
はより好ましいです。
|
||||
<literal>unique="true"</literal> の指定により、多重度が多対多から一対多
|
||||
に変わったことに注意して下さい。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses" table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
unique="true"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId not null, addressId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m21">
|
||||
<title>多対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>結合テーブルの単方向多対一関連</emphasis> は
|
||||
関連が任意であるときに非常に一般的なものです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId" unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-121">
|
||||
<title>一対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>結合テーブルの単方向一対一関連</emphasis> は、本当に特殊ですが
|
||||
不可能ではありません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-unidirectional-join-m2m">
|
||||
<title>多対多</title>
|
||||
|
||||
<para>
|
||||
最後に、<emphasis>単方向多対多関連</emphasis> を示します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses" table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-bidirectional" revision="1">
|
||||
<title>双方向関連</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-m21" revision="2">
|
||||
<title>一対多/多対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>双方向多対一関連</emphasis> は最も一般的な関連です。
|
||||
(標準的な親子関係です)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="people" inverse="true">
|
||||
<key column="addressId"/>
|
||||
<one-to-many class="Person"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>List</literal> (または他のインデックス付きのコレクション)を使うなら、
|
||||
外部キーの <literal>key</literal> カラムを <literal>not null</literal> に設定し、
|
||||
コレクション側が各要素のインデックスをメンテナンスするように、
|
||||
関連を扱う必要があります
|
||||
(<literal>update="false"</literal> かつ <literal>insert="false"</literal>
|
||||
と設定して、反対側を仮想的にinverseにします):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id"/>
|
||||
...
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"
|
||||
insert="false"
|
||||
update="false"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id"/>
|
||||
...
|
||||
<list name="people">
|
||||
<key column="addressId" not-null="true"/>
|
||||
<list-index column="peopleIdx"/>
|
||||
<one-to-many class="Person"/>
|
||||
</list>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
もし外部キーカラムが <literal>NOT NULL</literal> であるならば、
|
||||
コレクションマッピングの <literal><key></literal> 要素を
|
||||
<literal>not-null="true"</literal> にすることは重要です。
|
||||
入れ子になった <literal><column></literal> 要素だけではなく、
|
||||
<literal><key></literal> 要素も <literal>not-null="true"</literal>
|
||||
と定義しないようにしてください。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-121">
|
||||
<title>一対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>外部キーの双方向一対一関連</emphasis> は非常に一般的です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
unique="true"
|
||||
not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<one-to-one name="person"
|
||||
property-ref="address"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
<emphasis>主キーの双方向一対一関連</emphasis> は特殊なIDジェネレータを使います。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<one-to-one name="address"/>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="personId">
|
||||
<generator class="foreign">
|
||||
<param name="property">person</param>
|
||||
</generator>
|
||||
</id>
|
||||
<one-to-one name="person"
|
||||
constrained="true"/>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table Address ( personId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-bidirectional-join" revision="1">
|
||||
<title>結合テーブルを使った双方向関連</title>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-12m">
|
||||
<title>一対多/多対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>結合テーブルの双方向一対多関連</emphasis> です。
|
||||
<literal>inverse="true"</literal> が関連端、コレクション、結合のいずれかに
|
||||
設定できることに注意してください。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses"
|
||||
table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
unique="true"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
inverse="true"
|
||||
optional="true">
|
||||
<key column="addressId"/>
|
||||
<many-to-one name="person"
|
||||
column="personId"
|
||||
not-null="true"/>
|
||||
</join>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-121">
|
||||
<title>一対一</title>
|
||||
|
||||
<para>
|
||||
<emphasis>結合テーブルの双方向一対一関連</emphasis>
|
||||
は非常に特殊ですが、可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true">
|
||||
<key column="personId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="addressId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<join table="PersonAddress"
|
||||
optional="true"
|
||||
inverse="true">
|
||||
<key column="addressId"
|
||||
unique="true"/>
|
||||
<many-to-one name="address"
|
||||
column="personId"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
</join>
|
||||
</class>]]></programlisting>
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="assoc-bidirectional-join-m2m" revision="1">
|
||||
<title>多対多</title>
|
||||
|
||||
<para>
|
||||
最後に、<emphasis>双方向多対多関連</emphasis> を示します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id" column="personId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="addresses" table="PersonAddress">
|
||||
<key column="personId"/>
|
||||
<many-to-many column="addressId"
|
||||
class="Address"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
<id name="id" column="addressId">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<set name="people" inverse="true" table="PersonAddress">
|
||||
<key column="addressId"/>
|
||||
<many-to-many column="personId"
|
||||
class="Person"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
create table Person ( personId bigint not null primary key )
|
||||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||||
create table Address ( addressId bigint not null primary key )
|
||||
]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="assoc-complex">
|
||||
<title>より複雑な関連マッピング</title>
|
||||
|
||||
<para>
|
||||
より複雑な関連結合は <emphasis>極めて</emphasis> 稀です。
|
||||
マッピングドキュメントにSQL文を埋め込むことで、
|
||||
さらに複雑な状況を扱うことができます。
|
||||
例えば、<literal>accountNumber</literal>, <literal>effectiveEndDate</literal>,
|
||||
<literal>effectiveStartDate</literal> カラムを持つaccount(口座)情報の履歴を扱うテーブルは、
|
||||
以下のようにマッピングします。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<properties name="currentAccountKey">
|
||||
<property name="accountNumber" type="string" not-null="true"/>
|
||||
<property name="currentAccount" type="boolean">
|
||||
<formula>case when effectiveEndDate is null then 1 else 0 end</formula>
|
||||
</property>
|
||||
</properties>
|
||||
<property name="effectiveEndDate" type="date"/>
|
||||
<property name="effectiveStateDate" type="date" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
そして、関連を <emphasis>現時点の</emphasis> インスタンス
|
||||
(<literal>effectiveEndDate</literal> がnullであるもの)にマッピングします。
|
||||
以下のようになります:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="currentAccountInfo"
|
||||
property-ref="currentAccountKey"
|
||||
class="AccountInfo">
|
||||
<column name="accountNumber"/>
|
||||
<formula>'1'</formula>
|
||||
</many-to-one>]]></programlisting>
|
||||
|
||||
<para>
|
||||
さらに複雑な例では、<literal>Employee(従業員)</literal> と <literal>Organization(組織)</literal>
|
||||
間の関連が <literal>Employment(雇用)</literal> テーブルで保持される場合を想像してください。
|
||||
このテーブルには雇用データの履歴がすべて含まれます。
|
||||
すると従業員の <emphasis>最も最近の</emphasis> 雇用者を表す関連
|
||||
(最も最近の <literal>startDate</literal> を持つもの)は、このようにマッピングできます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<join>
|
||||
<key column="employeeId"/>
|
||||
<subselect>
|
||||
select employeeId, orgId
|
||||
from Employments
|
||||
group by orgId
|
||||
having startDate = max(startDate)
|
||||
</subselect>
|
||||
<many-to-one name="mostRecentEmployer"
|
||||
class="Organization"
|
||||
column="orgId"/>
|
||||
</join>]]></programlisting>
|
||||
|
||||
<para>
|
||||
この機能は非常に強力です。
|
||||
しかしこのような場合、普通はHQLやcriteriaクエリを使う方がより実践的です。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="batch">
|
||||
<title>バッチ処理</title>
|
||||
|
||||
<para>
|
||||
Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
for ( int i=0; i<100000; i++ ) {
|
||||
Customer customer = new Customer(.....);
|
||||
session.save(customer);
|
||||
}
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
これは50,000番目の行のあたりで <literal>OutOfMemoryException</literal> で失敗するでしょう。
|
||||
Hibernateがセッションレベルキャッシュで、
|
||||
新しく挿入されたすべての <literal>Customer</literal>
|
||||
インスタンスをキャッシュするからです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
この章では、この問題を回避する方法を紹介します。
|
||||
しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。
|
||||
そうでなければ手頃なパフォーマンスが得られません。
|
||||
JDBCバッチサイズを手頃な数値(例えば、10から50)に設定してください:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
|
||||
|
||||
<para>
|
||||
また二次キャッシュが全く効かないプロセスで、
|
||||
このような作業をしたいと思うかもしれません:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
|
||||
|
||||
<para>
|
||||
しかし、これは絶対に必要というわけではありません。
|
||||
なぜなら明示的に <literal>CacheMode</literal> を設定して、
|
||||
二次キャッシュとの相互作用を無効にすることができるからです。
|
||||
|
||||
</para>
|
||||
|
||||
<sect1 id="batch-inserts">
|
||||
<title>バッチ挿入</title>
|
||||
|
||||
<para>
|
||||
新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、
|
||||
セッションを <literal>flush()</literal> して <literal>clear()</literal>
|
||||
しなければなりません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
for ( int i=0; i<100000; i++ ) {
|
||||
Customer customer = new Customer(.....);
|
||||
session.save(customer);
|
||||
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
|
||||
//flush a batch of inserts and release memory:
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-update" >
|
||||
<title>バッチ更新</title>
|
||||
|
||||
<para>
|
||||
データを復元したり更新したりするには同じアイディアを適用します。
|
||||
それに加えて、データの行を多く返すクエリに対して有効な
|
||||
サーバーサイドのカーソルの利点を生かしたければ
|
||||
<literal>scroll()</literal> を使う必要があります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
ScrollableResults customers = session.getNamedQuery("GetCustomers")
|
||||
.setCacheMode(CacheMode.IGNORE)
|
||||
.scroll(ScrollMode.FORWARD_ONLY);
|
||||
int count=0;
|
||||
while ( customers.next() ) {
|
||||
Customer customer = (Customer) customers.get(0);
|
||||
customer.updateStuff(...);
|
||||
if ( ++count % 20 == 0 ) {
|
||||
//flush a batch of updates and release memory:
|
||||
session.flush();
|
||||
session.clear();
|
||||
}
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-statelesssession">
|
||||
<title>
|
||||
StatelessSessionインターフェイス
|
||||
</title>
|
||||
|
||||
<para>
|
||||
また別の方法として、Hibernateはコマンド指向のAPIを用意しています。
|
||||
これは分離オブジェクトの形で、
|
||||
データベースとのデータストリームのやり取りに使うことができます。
|
||||
<literal>StatelessSession</literal> は関連する永続コンテキストを持たず、
|
||||
高レベルのライフサイクルセマンティクスの多くを提供しません。
|
||||
特にステートレスセッションは、一時キャッシュを実装せず、
|
||||
またどのような二次キャッシュやクエリキャッシュとも相互作用しません。
|
||||
トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。
|
||||
ステートレスセッションを使って行われる操作が、
|
||||
関連するインスタンスへカスケードされることは決してありません。
|
||||
コレクションは、ステートレスセッションからは無視されます。
|
||||
ステートレスセッションを通して行われる操作は、
|
||||
Hibernateのイベントモデルやインターセプタの影響を受けません。
|
||||
一時キャッシュを持たないため、
|
||||
ステートレスセッションは別名を持つデータに上手く対処できません。
|
||||
ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
|
||||
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[StatelessSession session = sessionFactory.openStatelessSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
ScrollableResults customers = session.getNamedQuery("GetCustomers")
|
||||
.scroll(ScrollMode.FORWARD_ONLY);
|
||||
while ( customers.next() ) {
|
||||
Customer customer = (Customer) customers.get(0);
|
||||
customer.updateStuff(...);
|
||||
session.update(customer);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
このコード例では、クエリが返す <literal>Customer</literal>
|
||||
インスタンスは即座に(セッションから)分離されることに注意してください。
|
||||
これは、どのような永続コンテキストとも決して関連しません。
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>StatelessSession</literal> インターフェイスで定義されている
|
||||
<literal>insert(), update(), delete()</literal> は、
|
||||
低レベルの直接的なデータベース操作と考えられます。
|
||||
結果として、SQLの <literal>INSERT, UPDATE, DELETE</literal> がそれぞれ即座に実行されます。
|
||||
このように、これらは <literal>Session</literal> インターフェイスで定義されている
|
||||
<literal>save(), saveOrUpdate(), delete()</literal>
|
||||
とは非常に異なる意味を持ちます。
|
||||
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="batch-direct" revision="3">
|
||||
<title>
|
||||
DMLスタイルの操作
|
||||
</title>
|
||||
|
||||
<para>
|
||||
すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、
|
||||
オブジェクトの状態の管理であると考えられます。
|
||||
これはメモリ内のオブジェクトの状態を利用できるということです。
|
||||
そのため(SQLの <literal>データ操作言語</literal> (DML) 文:
|
||||
<literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>
|
||||
を使って)データベース内のデータを直接操作しても、
|
||||
メモリ内の状態には影響を与えません。
|
||||
しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。
|
||||
これはHibernateクエリ言語(<xref linkend="queryhql">HQL</xref>)
|
||||
を通して実行されます。
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>UPDATE</literal> と <literal>DELETE</literal> 文の疑似構文は:
|
||||
<literal>( UPDATE | DELETE ) FROM? エンティティ名 (WHERE 条件節)?</literal> です。
|
||||
注意すべき点がいくつかあります:
|
||||
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
from節において、FROMキーワードはオプションです。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
from節では単一のエンティティ名だけが可能で、
|
||||
任意で別名を付けることができます。
|
||||
エンティティ名に別名が与えられると、どのようなプロパティ参照も、
|
||||
その別名を使って修飾しなければなりません。
|
||||
もしエンティティ名に別名が与えられなければ、
|
||||
どのようなプロパティ参照も修飾してはなりません。
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
(暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合</xref>
|
||||
をバルクHQLクエリ内で指定することはできません。
|
||||
サブクエリはwhere節で使うことができます
|
||||
サブクエリそのものは、結合を含められます。
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
where節はオプションです。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
例として、HQLの <literal>UPDATE</literal> を実行するには、
|
||||
<literal>Query.executeUpdate()</literal> メソッドを使ってください。
|
||||
(このメソッドはおなじみのJDBC <literal>PreparedStatement.executeUpdate()</literal>
|
||||
から名付けられました):
|
||||
d
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = s.createQuery( hqlUpdate )
|
||||
.setString( "newName", newName )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
HQLの <literal>UPDATE</literal> 文は、デフォルトでは、作用するエンティティの
|
||||
<xref linkend="mapping-declaration-version">version</xref> や
|
||||
<xref linkend="mapping-declaration-timestamp">timestamp</xref>
|
||||
プロパティの値には影響しません。
|
||||
これはEJB3の仕様にも受け継がれています。
|
||||
しかし <literal>versioned update</literal> を使って、
|
||||
<literal>version</literal> や <literal>timestamp</literal>
|
||||
プロパティの値を強制的にリセットさせることができます。
|
||||
これは <literal>UPDATE</literal> キーワードの後に <literal>VERSIONED</literal>
|
||||
キーワードを追加することで行えます。
|
||||
|
||||
</para>
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = s.createQuery( hqlUpdate )
|
||||
.setString( "newName", newName )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
カスタムバージョン型(<literal>org.hibernate.usertype.UserVersionType</literal>)
|
||||
は <literal>update versioned</literal> 文と一緒に使えないことに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HQLの <literal>DELETE</literal> を実行するには、
|
||||
同じ <literal>Query.executeUpdate()</literal> メソッドを使ってください:
|
||||
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
String hqlDelete = "delete Customer c where c.name = :oldName";
|
||||
// or String hqlDelete = "delete Customer where name = :oldName";
|
||||
int deletedEntities = s.createQuery( hqlDelete )
|
||||
.setString( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Query.executeUpdate()</literal> メソッドが返す <literal>int</literal>
|
||||
の値は、この操作が影響を及ぼしたエンティティの数です。
|
||||
これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。
|
||||
HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。
|
||||
例えばjoined-subclassです。
|
||||
返される数は、その文によって影響された実際のエンティティの数を示します。
|
||||
joined-subclassの例に戻ると、サブクラスの一つに対する削除は、
|
||||
そのサブクラスがマッピングされたテーブルだけではなく、
|
||||
「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>INSERT</literal> 文の疑似構文は:
|
||||
<literal>INSERT INTO エンティティ名 プロパティリスト select文</literal> です。
|
||||
注意すべき点がいくつかあります:
|
||||
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
INSERT INTO ... SELECT ... の形式だけがサポートされています。
|
||||
INSERT INTO ... VALUES ... の形式はサポートされていません。
|
||||
</para>
|
||||
<para>
|
||||
プロパティリストは、SQLの <literal>INSERT</literal> 文における <literal>カラムの仕様</literal>
|
||||
に類似しています。
|
||||
継承のマッピングに含まれるエンティティに対して、
|
||||
クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。
|
||||
スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。
|
||||
言い換えると <literal>INSERT</literal> 文は、本質的にポリモーフィックではありません。
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
select文の返り値の型がinsert文が期待する型とマッチしていれば、
|
||||
そのselect文は妥当なHQL selectクエリとなりえます。
|
||||
現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。
|
||||
このことは、<emphasis>equal</emphasis>とは違い、
|
||||
Hibernateの <literal>Type</literal> 間の <emphasis>equivalent</emphasis> に関する
|
||||
問題を引き起こすことに注意してください。
|
||||
これは <literal>org.hibernate.type.DataType</literal> として定義されたプロパティと、
|
||||
<literal>org.hibernate.type.TimestampType</literal>
|
||||
として定義されたプロパティの間のミスマッチの問題を引き起こします。
|
||||
データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
idプロパティに対して、insert文には二つの選択肢があります。
|
||||
プロパティリストで明示的にidプロパティを指定するか
|
||||
(この場合、対応するselect式から値が取られます)、
|
||||
プロパティリストから除外するか
|
||||
(この場合、生成される値が使われます)のいずれかです。
|
||||
後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。
|
||||
この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。
|
||||
この議論では、インデータベース型ジェネレータは <literal>org.hibernate.id.SequenceGenerator</literal>
|
||||
(とそのサブクラス)と、<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>
|
||||
の実装であると考えています。
|
||||
ここで最も注意すべき例外は、<literal>org.hibernate.id.TableHiLoGenerator</literal> です。
|
||||
値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>version</literal> や <literal>timestamp</literal> としてマッピングされるプロパティに対して、
|
||||
insert文には二つの選択肢があります。
|
||||
プロパティリストで明示的にプロパティを指定するか
|
||||
(この場合、対応するselect式から値が取られます)、
|
||||
プロパティリストから除外するか
|
||||
(この場合、<literal>org.hibernate.type.VersionType</literal> で定義された
|
||||
<literal>シード値</literal> が使われます)のいずれかです。
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
HQLの <literal>INSERT</literal> 文の実行例です:
|
||||
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sessionFactory.openSession();
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
|
||||
int createdEntities = s.createQuery( hqlInsert )
|
||||
.executeUpdate();
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,250 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="best-practices" revision="3">
|
||||
<title>ベストプラクティス</title>
|
||||
|
||||
<variablelist spacing="compact">
|
||||
<varlistentry>
|
||||
<term>
|
||||
クラスは細かい粒度で書き <literal><component></literal> でマッピングしましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>street</literal>(通り), <literal>suburb</literal>
|
||||
(都市), <literal>state</literal>(州), <literal>postcode</literal>
|
||||
(郵便番号)をカプセル化する <literal>Address</literal>(住所)クラスを使いましょう。
|
||||
そうすればコードが再利用しやすくなり、リファクタリングも簡単になります。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
永続クラスには識別子プロパティを定義しましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernateでは識別子プロパティはオプションですが、
|
||||
使用すべき理由がたくさんあります。
|
||||
識別子は「人工的」(生成された、業務的な意味を持たない)
|
||||
なものにすることをおすすめします。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>自然キーを見つけましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
すべてのエンティティに対して自然キーを見つけて、
|
||||
<literal><natural-id></literal> でマッピングしましょう。
|
||||
自然キーを構成するプロパティを比較するために、
|
||||
<literal>equals()</literal> と <literal>hashCode()</literal> を実装しましょう。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>クラスのマッピングはそれぞれのクラス専用のファイルに書きましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
単一の巨大なマッピングドキュメントを使用しないでください。
|
||||
<literal>com.eg.Foo</literal> クラスなら
|
||||
<literal>com/eg/Foo.hbm.xml</literal> ファイルにマッピングしましょう。
|
||||
このことは、特にチームでの開発に意味があります。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>リソースとしてマッピングをロードしましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
マッピングを、それらがマッピングするするクラスと一緒に配置しましょう。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>クエリ文字列を外部に置くことを考えましょう</term>
|
||||
<listitem>
|
||||
<para>
|
||||
クエリがANSI標準でないSQL関数を呼んでいるなら、これはよいプラクティスです。
|
||||
クエリ文字列をマッピングファイルへ外出しすればアプリケーションがポータブルになります。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>バインド変数を使いましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
JDBCの場合と同じように、定数でない値は必ず"?"で置き換えましょう。
|
||||
定数でない値をバインドするために、クエリで文字列操作を使ってはいけません。
|
||||
名前付きのパラメータを使うようにするとさらに良いです。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>JDBCコネクションを管理してはいけません。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
HibernateではアプリケーションがJDBCコネクションを管理することが許されています。
|
||||
しかしこれは最終手段だと思ってください。
|
||||
組み込みのコネクションプロバイダを使うことができなければ、
|
||||
<literal>org.hibernate.connection.ConnectionProvider</literal> を実装することを考えてください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>カスタム型の使用を考えましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
あるライブラリから持ってきたJava型を永続化する必要があるとしましょう。
|
||||
しかしその型には、コンポーネントとしてマッピングするために必要なアクセサがないとします。
|
||||
このような場合は <literal>org.hibernate.UserType</literal> の実装を考えるべきです。
|
||||
そうすればHibernate型との実装変換を心配せずにアプリケーションのコードを扱えます。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>ボトルネックを解消するにはJDBCをハンドコードしましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
システムのパフォーマンスクリティカルな領域では、
|
||||
ある種の操作にJDBCを直接使うと良いかもしれません。
|
||||
しかし何がボトルネックになっているか <emphasis>はっきりする</emphasis> までは待ってください。
|
||||
またJDBCを直接使うからといって、必ずしも速くなるとは限らないことも理解してください。
|
||||
JDBCを直接使う必要があれば、Hibernateの <literal>Session</literal> をオープンして、
|
||||
JDBCコネクションを使うと良いかもしれません。
|
||||
依然として同じトランザクション戦略とコネクションプロバイダが使えるからです。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><literal>Session</literal> のフラッシュを理解しましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Sessionが永続状態をデータベースと同期させることがときどきあります。
|
||||
しかしこれがあまりに頻繁に起こるようだと、パフォーマンスに影響が出てきます。
|
||||
自動フラッシュを無効にしたり、特定のトランザクションのクエリや操作の順番を変更することで、
|
||||
不必要なフラッシュを最小限にできます。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>3層アーキテクチャでは分離オブジェクトの使用を考えましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
サーブレット / セッションビーンアーキテクチャを使うとき、
|
||||
サーブレット層 / JSP層間でセッションビーンでロードした永続オブジェクトをやり取りできます。
|
||||
その際リクエストごとに新しいSessionを使ってください。
|
||||
また <literal>Session.merge()</literal> や <literal>Session.saveOrUpdate()</literal>
|
||||
を使って、オブジェクトとデータベースを同期させてください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>2層アーキテクチャでは長い永続コンテキストの使用を考えましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
最高のスケーラビリティを得るには、
|
||||
データベーストランザクションをできるだけ短くしなければなりません。
|
||||
しかし長い間実行する <emphasis>アプリケーショントランザクション</emphasis>
|
||||
の実装が必要なことはしばしばです。
|
||||
これはユーザの視点からは1個の作業単位(unit of work)になります。
|
||||
アプリケーショントランザクションはいくつかのクライアントのリクエスト/レスポンスサイクルにまたがります。
|
||||
アプリケーショントランザクションの実装に分離オブジェクトを使うのは一般的です。
|
||||
|
||||
そうでなければ、2層アーキテクチャの場合は特に適切なことですが、
|
||||
アプリケーショントランザクションのライフサイクル全体に対して
|
||||
単一のオープンな永続化コンテキスト(セッション)を維持してください。
|
||||
そして単純にリクエストの最後にJDBCコネクションから切断し、
|
||||
次のリクエストの最初に再接続します。
|
||||
|
||||
決して複数のアプリケーショントランザクションユースケースに渡って
|
||||
1個のSessionを使い回さないでください。
|
||||
そうでなければ、古いデータで作業することになります。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>例外を復帰可能なものとして扱ってはいけません。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
これは「ベスト」プラクティス以上の、必須のプラクティスです。
|
||||
例外が発生したときは <literal>Transaction</literal> をロールバックして、
|
||||
<literal>Session</literal> をクローズしてください。
|
||||
そうしないとHibernateはメモリの状態が永続状態を正確に表現していることを保証できません。
|
||||
この特別な場合として、与えられた識別子を持つインスタンスがデータベースに存在するかどうかを判定するために、
|
||||
<literal>Session.load()</literal> を使うことはやめてください。
|
||||
その代わりに <literal>Session.get()</literal> かクエリを使ってください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>関連にはなるべく遅延フェッチを使いましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
即時フェッチは控えめにしましょう。
|
||||
二次キャッシュには完全に保持されないようなクラスの関連には、
|
||||
プロキシと遅延コレクションを使ってください。
|
||||
キャッシュされるクラスの関連、つまりキャッシュがヒットする可能性が非常に高い関連は、
|
||||
<literal>lazy="false"</literal> で積極的なフェッチを明示的に無効にしてください。
|
||||
結合フェッチが適切な特定のユースケースには、
|
||||
クエリで <literal>left join fetch</literal> を使ってください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>
|
||||
フェッチされていないデータに関わる問題を避けるために、
|
||||
<emphasis>ビューの中でオープンセッションを使う(open session in view)</emphasis>
|
||||
パターンか、統制された <emphasis>組み立てフェーズ(assembly phase)</emphasis> を使いましょう。
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Hibernateは <emphasis>Data Transfer Objects</emphasis> (DTO)を書く退屈な作業から開発者を解放します。
|
||||
伝統的なEJBアーキテクチャではDTOは二つ目的があります:
|
||||
1つ目は、エンティティビーンがシリアライズされない問題への対策です。
|
||||
2つ目は、プレゼンテーション層に制御が戻る前に、
|
||||
ビューに使われるすべてのデータがフェッチされて、DTOに復元されるような組み立てフェーズを暗黙的に定義します。
|
||||
Hibernateでは1つ目の目的が不要になります。
|
||||
しかしビューのレンダリング処理の間、永続コンテキスト(セッション)をオープンにしたままにしなければ、
|
||||
組み立てフェーズはまだ必要です(分離オブジェクトの中のどのデータが利用可能かについて、
|
||||
プレゼンテーション層と厳密な取り決めをしているビジネスメソッドを考えてみてください)。
|
||||
これはHibernate側の問題ではありません。
|
||||
トランザクション内で安全にデータアクセスするための基本的な要件です。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Hibernateからビジネスロジックを抽象化することを考えましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
インターフェイスで(Hibernateの)データアクセスコードを隠蔽しましょう。
|
||||
<emphasis>DAO</emphasis> と <emphasis>Thread Local Session</emphasis> パターンを組み合わせましょう。
|
||||
<literal>UserType</literal> でHibernateに関連付けると、
|
||||
ハンドコードしたJDBCで永続化するクラスを持つこともできます。
|
||||
(このアドバイスは「十分大きな」アプリケーションに対してのものです。
|
||||
テーブルが5個しかないようなアプリケーションには当てはまりません。)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>珍しい関連マッピングは使わないようにしましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
よいユースケースに本当の多対多関連があることは稀(まれ)です。
|
||||
ほとんどの場合「リンクテーブル」の付加的な情報が必要になります。
|
||||
この場合、リンククラスに2つの1対多関連を使う方がずっと良いです。
|
||||
実際ほとんどの場合関連は1対多と多対1なので、
|
||||
他のスタイルの関連を使うときは本当に必要かどうかを考えてみてください。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>なるべく双方向関連にしましょう。</term>
|
||||
<listitem>
|
||||
<para>
|
||||
単方向関連は双方向に比べて検索が難しくなります。
|
||||
大きなアプリケーションでは、
|
||||
ほとんどすべての関連が双方向にナビゲーションできなければなりません。
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="components">
|
||||
<title>コンポーネントのマッピング</title>
|
||||
|
||||
<para>
|
||||
<emphasis>コンポーネント</emphasis> の概念は、Hibernateを通して様々な状況の中で
|
||||
異なる目的のために再利用されます。
|
||||
</para>
|
||||
|
||||
<sect1 id="components-dependentobjects" revision="2" >
|
||||
<title>依存オブジェクト</title>
|
||||
|
||||
<para>
|
||||
コンポーネントは、エンティティの参照ではなく値型として永続化された、
|
||||
包含されたオブジェクトです。コンポーネントという言葉については、コンポジションという
|
||||
オブジェクト指向の概念を参照してください(アーキテクチャレベルのコンポーネントではありません)。
|
||||
例えば、以下のPersonモデルのようなものです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Person {
|
||||
private java.util.Date birthday;
|
||||
private Name name;
|
||||
private String key;
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
private void setKey(String key) {
|
||||
this.key=key;
|
||||
}
|
||||
public java.util.Date getBirthday() {
|
||||
return birthday;
|
||||
}
|
||||
public void setBirthday(java.util.Date birthday) {
|
||||
this.birthday = birthday;
|
||||
}
|
||||
public Name getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(Name name) {
|
||||
this.name = name;
|
||||
}
|
||||
......
|
||||
......
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[public class Name {
|
||||
char initial;
|
||||
String first;
|
||||
String last;
|
||||
public String getFirst() {
|
||||
return first;
|
||||
}
|
||||
void setFirst(String first) {
|
||||
this.first = first;
|
||||
}
|
||||
public String getLast() {
|
||||
return last;
|
||||
}
|
||||
void setLast(String last) {
|
||||
this.last = last;
|
||||
}
|
||||
public char getInitial() {
|
||||
return initial;
|
||||
}
|
||||
void setInitial(char initial) {
|
||||
this.initial = initial;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
いま、<literal>Name</literal> は <literal>Person</literal> のコンポーネントとして
|
||||
永続化することが出来ます。ここで <literal>Name</literal> は永続化属性に対してgetter、
|
||||
setterメソッドを定義しますが、インターフェイスや識別子プロパティを定義する必要が
|
||||
ないことに注意して下さい。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
マッピング定義は以下のようになります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<id name="Key" column="pid" type="string">
|
||||
<generator class="uuid"/>
|
||||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name"> <!-- class attribute optional -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
Personテーブルは <literal>pid</literal>、
|
||||
<literal>birthday</literal>、
|
||||
<literal>initial</literal>、
|
||||
<literal>first</literal>、
|
||||
<literal>last</literal> カラムを持ちます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
全ての値型のように、コンポーネントは参照の共有をすることができません。
|
||||
言い換えると、二人のPersonは同じ名前を持つことができますが、二つのPersonオブジェクトは
|
||||
"値が同じだけ"の別々のnameオブジェクトを含んでいるということです。
|
||||
コンポーネントのnull値のセマンティクスは <emphasis>アドホック</emphasis> です。
|
||||
コンポーネントのオブジェクトを再読み込みする際、Hibernateはコンポーネントのすべてのカラムが
|
||||
nullであるならコンポーネント自体がnullであると考えます。
|
||||
これは大抵の場合問題ありません。
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
コンポーネントの属性はどんなHibernateの型でも構いません(コレクション、many-to-one関連、
|
||||
他のコンポーネントなど)。ネストされたコンポーネントは滅多に使わないと考えるべきでは
|
||||
<emphasis>ありません</emphasis> 。Hibernateは非常にきめの細かいオブジェクトモデルをサポートするように意図されています。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal><component></literal> 要素は親エンティティへの逆参照として、コンポーネントクラスの
|
||||
属性をマッピングする <literal><parent></literal> サブ要素を使用できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Person" table="person">
|
||||
<id name="Key" column="pid" type="string">
|
||||
<generator class="uuid"/>
|
||||
</id>
|
||||
<property name="birthday" type="date"/>
|
||||
<component name="Name" class="eg.Name" unique="true">
|
||||
<parent name="namedPerson"/> <!-- reference back to the Person -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</component>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-incollections" revision="1">
|
||||
|
||||
<title>従属するオブジェクトのコレクション</title>
|
||||
|
||||
<para>
|
||||
Hibernateはコンポーネントのコレクションをサポートしています(例えば <literal>Name</literal> 型の配列)。
|
||||
<literal><element></literal> タグを <literal><composite-element></literal> タグに取り替えることにより
|
||||
コンポーネントコレクションを宣言してください。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
|
||||
<key column="id"/>
|
||||
<composite-element class="eg.Name"> <!-- class attribute required -->
|
||||
<property name="initial"/>
|
||||
<property name="first"/>
|
||||
<property name="last"/>
|
||||
</composite-element>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
注意: コンポジットエレメントの <literal>Set</literal> を定義したなら、
|
||||
<literal>equals()</literal> と <literal>hashCode()</literal> を正しく実装することが重要です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
コンポジットエレメントはコレクションを含まず、コンポーネントを含むこともあります。
|
||||
コンポジットエレメント自身がコンポーネントを含んでいる場合は <literal><nested-composite-element></literal> を
|
||||
使用してください。コンポーネントのコレクション自身がコンポーネントを持つというケースはめったにありません。
|
||||
この段階までに、one-to-many関連の方がより適切でないかと熟考してください。
|
||||
コンポジットエレメントをエンティティとして再度モデリングしてみてください。
|
||||
しかしこれはJavaのモデルとしては同じですが、リレーショナルモデルと永続動作はまだ若干異なることに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
もし <literal><set></literal> を使用するのであれば、コンポジットエレメントのマッピングがnull値が可能な
|
||||
属性をサポートしていないことに注意してください。Hibernateはオブジェクトを削除するとき、
|
||||
レコードを識別するためにそれぞれのカラムの値を使用する必要があるため、null値を持つことが出来ません
|
||||
(コンポジットエレメントテーブルには別の主キーカラムはありません)。
|
||||
コンポジットエレメントにnot-nullの属性のみを使用するか、または <literal><list></literal>、<literal><map></literal>、
|
||||
<literal><bag></literal>、<literal><idbag></literal> を選択する必要があります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
コンポジットエレメントの特別なケースとして、ネストされた <literal><many-to-one></literal> 属性を持つ
|
||||
コンポジットエレメントがあります。
|
||||
このマッピングは、コンポジットエレメントクラスを多対多関連テーブルの
|
||||
余分なカラムへマッピングします。
|
||||
次の例は <literal>Order</literal> から、<literal>Item</literal> への多対多関連です。
|
||||
<literal>purchaseDate</literal>、<literal>price</literal>、<literal>quantity</literal> は関連の属性となります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
<composite-element class="eg.Purchase">
|
||||
<property name="purchaseDate"/>
|
||||
<property name="price"/>
|
||||
<property name="quantity"/>
|
||||
<many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
もちろん、双方向関連のナビゲーションのために反対側からpurchaseへの参照を作ることは出来ません。
|
||||
コンポーネントは値型であり、参照を共有できないことを覚えておいてください。
|
||||
一つの <literal>Purchase</literal> は一つの <literal>Order</literal> のsetに存在できますが、
|
||||
同時に <literal>Item</literal> から参照することは出来ません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
3項関連(あるいは4項など)も可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="eg.Order" .... >
|
||||
....
|
||||
<set name="purchasedItems" table="purchase_items" lazy="true">
|
||||
<key column="order_id">
|
||||
<composite-element class="eg.OrderLine">
|
||||
<many-to-one name="purchaseDetails" class="eg.Purchase"/>
|
||||
<many-to-one name="item" class="eg.Item"/>
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
コンポジットエレメントは他のエンティティへの関連として、
|
||||
同じシンタックスを使っているクエリ内で使用できます。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-asmapindex">
|
||||
<title>Mapのインデックスとしてのコンポーネント</title>
|
||||
|
||||
<para>
|
||||
<literal><composite-map-key></literal> 要素は <literal>Map</literal> のキーとしてコンポーネントクラスを
|
||||
マッピングします。コンポーネントクラス上で <literal>hashCode()</literal> と <literal>equals()</literal>
|
||||
を正確にオーバーライドしてください。
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-compositeid" revision="1">
|
||||
<title>複合識別子としてのコンポーネント</title>
|
||||
|
||||
<para>
|
||||
コンポーネントをエンティティクラスの識別子として使うことができます。
|
||||
コンポーネントクラスは以下の条件を満たす必要があります。
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>java.io.Serializable</literal> を実装しなければなりません。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
データベース上の複合キーの等価性と矛盾のないように、<literal>equals()</literal>
|
||||
と <literal>hashCode()</literal> を再実装しなければなりません。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
<emphasis>注意: Hibernate3において、2番目の条件は絶対的な条件ではありません。
|
||||
しかしとにかく条件を満たしてください。
|
||||
</emphasis>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
複合キーを生成するために <literal>IdentifierGenerator</literal> を使用することはできません。
|
||||
代わりにアプリケーションが識別子を割り当てなくてはなりません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
通常の <literal><id></literal> 宣言の代わりに <literal><composite-id></literal> タグを
|
||||
(ネストされた <literal><key-property></literal> 属性と共に)使います。
|
||||
以下の例では、<literal>OrderLine</literal> クラスは <literal>Order</literal> の(複合)主キーに
|
||||
依存した主キーを持っています。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
|
||||
<composite-id name="id" class="OrderLineId">
|
||||
<key-property name="lineId"/>
|
||||
<key-property name="orderId"/>
|
||||
<key-property name="customerId"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="name"/>
|
||||
|
||||
<many-to-one name="order" class="Order"
|
||||
insert="false" update="false">
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-one>
|
||||
....
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
このとき、<literal>OrderLine</literal> テーブルへ関連する外部キーもまた複合です。
|
||||
他のクラスのマッピングでこれを宣言しなければなりません。
|
||||
<literal>OrderLine</literal> への関連は次のようにマッピングされます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
|
||||
<!-- the "class" attribute is optional, as usual -->
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-one>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal><column></literal> タグはどこであっても <literal>column</literal> 属性の
|
||||
代わりになります。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>OrderLine</literal> への <literal>many-to-many</literal> 関連も
|
||||
複合外部キーを使います。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="undeliveredOrderLines">
|
||||
<key column name="warehouseId"/>
|
||||
<many-to-many class="OrderLine">
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</many-to-many>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Order</literal> にある <literal>OrderLine</literal> のコレクションは
|
||||
次のものを使用します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="orderLines" inverse="true">
|
||||
<key>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</key>
|
||||
<one-to-many class="OrderLine"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal><one-to-many></literal> 属性は、例によってカラムを宣言しません)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>OrderLine</literal> 自身がコレクションを持っている場合、
|
||||
同時に複合外部キーも持っています。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="OrderLine">
|
||||
....
|
||||
....
|
||||
<list name="deliveryAttempts">
|
||||
<key> <!-- a collection inherits the composite key type -->
|
||||
<column name="lineId"/>
|
||||
<column name="orderId"/>
|
||||
<column name="customerId"/>
|
||||
</key>
|
||||
<list-index column="attemptId" base="1"/>
|
||||
<composite-element class="DeliveryAttempt">
|
||||
...
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="components-dynamic" revision="1">
|
||||
<title>動的コンポーネント</title>
|
||||
|
||||
<para>
|
||||
<literal>Map</literal> 型のプロパティのマッピングも可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<dynamic-component name="userAttributes">
|
||||
<property name="foo" column="FOO" type="string"/>
|
||||
<property name="bar" column="BAR" type="integer"/>
|
||||
<many-to-one name="baz" class="Baz" column="BAZ_ID"/>
|
||||
</dynamic-component>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal><dynamic-component></literal> マッピングのセマンティクスは <literal><component></literal>
|
||||
と同一のものです。この種のマッピングの利点は、マッピングドキュメントの編集により、配置時にbeanの属性を
|
||||
決定できる点です。また、DOMパーサを利用して、マッピングドキュメントのランタイム操作が可能です。
|
||||
さらに、<literal>Configuration</literal> オブジェクト経由でHibernateのコンフィグレーション時のメタモデルに
|
||||
アクセス(または変更)が可能です。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,274 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="events">
|
||||
<title>インターセプタとイベント</title>
|
||||
|
||||
<para>
|
||||
アプリケーションがHibernateの内部で発生するイベントに対応できると役に立つことがあります。
|
||||
ある種の一般的な機能を実装できるようになり、
|
||||
またHibernateの機能を拡張することもできるようになります。
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-interceptors" revision="3">
|
||||
<title>インターセプタ</title>
|
||||
|
||||
<para>
|
||||
<literal>Interceptor</literal> インターフェイスを使って、
|
||||
セッションからアプリケーションへコールバックをすることができます。
|
||||
これにより永続オブジェクトの保存、更新、削除、読み込みの前に、
|
||||
アプリケーションがプロパティを検査したり操作したりできるようになります。
|
||||
これは監査情報の追跡に利用できます。
|
||||
下の例で <literal>Interceptor</literal> は <literal>Auditable</literal>
|
||||
が作成されると自動的に <literal>createTimestamp</literal> を設定し、
|
||||
<literal>Auditable</literal> が更新されると自動的に
|
||||
<literal>lastUpdateTimestamp</literal> プロパティを更新します。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Interceptor</literal> を直接実装したり、
|
||||
(さらによいのは)<literal>EmptyInterceptor</literal> を拡張したりできます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package org.hibernate.test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.EmptyInterceptor;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
public class AuditInterceptor extends EmptyInterceptor {
|
||||
|
||||
private int updates;
|
||||
private int creates;
|
||||
private int loads;
|
||||
|
||||
public void onDelete(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public boolean onFlushDirty(Object entity,
|
||||
Serializable id,
|
||||
Object[] currentState,
|
||||
Object[] previousState,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if ( entity instanceof Auditable ) {
|
||||
updates++;
|
||||
for ( int i=0; i < propertyNames.length; i++ ) {
|
||||
if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
|
||||
currentState[i] = new Date();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onLoad(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
if ( entity instanceof Auditable ) {
|
||||
loads++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSave(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if ( entity instanceof Auditable ) {
|
||||
creates++;
|
||||
for ( int i=0; i<propertyNames.length; i++ ) {
|
||||
if ( "createTimestamp".equals( propertyNames[i] ) ) {
|
||||
state[i] = new Date();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void afterTransactionCompletion(Transaction tx) {
|
||||
if ( tx.wasCommitted() ) {
|
||||
System.out.println("Creations: " + creates + ", Updates: " + updates, "Loads: " + loads);
|
||||
}
|
||||
updates=0;
|
||||
creates=0;
|
||||
loads=0;
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
インターセプタには二種類あります:
|
||||
<literal>Session</literal> スコープのものと
|
||||
<literal>SessionFactory</literal> スコープのものです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal> スコープのインターセプタは、
|
||||
セッションをオープンするときに指定します。
|
||||
<literal>Interceptor</literal> を引数に取るSessionFactory.openSession()
|
||||
のオーバーロードメソッドの一つを使います。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal> スコープのインターセプタは <literal>Configuration</literal>
|
||||
オブジェクトを使って登録します。
|
||||
これは <literal>SessionFactory</literal> の構築よりも優先されます。
|
||||
この場合、提供されるインターセプタは <literal>SessionFactory</literal>
|
||||
からオープンされたすべてのセッションに適用されます。
|
||||
これは使用するインターセプタを明示的に指定してセッションをオープンしない限り、そうなります。
|
||||
<literal>SessionFactory</literal> スコープのインターセプタはスレッドセーフでなければなりません。
|
||||
複数のセッションが(潜在的に)このインターセプタを同時並行で使用することになるため、
|
||||
セッション固有の状態を格納しないように気をつけてください。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-events" revision="4">
|
||||
<title>イベントシステム</title>
|
||||
|
||||
<para>
|
||||
永続化層で特定のイベントに対応しなければならない場合、
|
||||
Hibernate3の <emphasis>イベント</emphasis> アーキテクチャを使うこともできます。
|
||||
イベントシステムはインターセプタと一緒に使うか、またはインターセプタの代わりとして使うことができます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
本質的に <literal>Session</literal> インターフェイスのすべてのメソッドは、
|
||||
1個のイベントと相互に関連します。
|
||||
例えば <literal>LoadEvent</literal>、<literal>FlushEvent</literal> などがあります
|
||||
(定義済みのイベント型の一覧については、XML設定ファイルのDTDや
|
||||
<literal>org.hibernate.event</literal> パッケージを調べてください)。
|
||||
リクエストがこれらのメソッドの1つから作られるとき、
|
||||
Hibernateの <literal>Session</literal> は適切なイベントを生成し、
|
||||
そのイベント型に設定されたイベントリスナに渡します。
|
||||
すばらしいことに、これらのリスナはそのメソッドと同じ処理を実装します。
|
||||
とはいえ、リスナインターフェイスの一つを自由にカスタム実装できます
|
||||
(つまり、<literal>LoadEvent</literal> は登録された <literal>LoadEventListener</literal>
|
||||
インターフェイスの実装により処理されます)。
|
||||
その場合、その実装には <literal>Session</literal> から作られたどのような <literal>load()</literal>
|
||||
リクエストをも処理する責任があります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
リスナは事実上シングルトンであると見なせます。
|
||||
つまりリスナはリクエスト間で共有されるため、
|
||||
インスタンス変数として状態を保持するべきではないということです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
カスタムリスナは処理したいイベントについて適切なインターフェイスを実装するべきです。
|
||||
便利な基底クラスのうちの一つを継承してもよいです
|
||||
(またはHibernateがデフォルトで使用するイベントリスナを継承してもよいです。
|
||||
すばらしいことに、この目的のために非finalとして宣言されています)。
|
||||
カスタムリスナは <literal>Configuration</literal> オブジェクトを使ってプログラムから登録するか、
|
||||
HibernateのXML設定ファイルで指定できます
|
||||
(プロパティファイルで宣言的に設定する方法はサポートされていません)。
|
||||
カスタムロードイベントリスナの例を示します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class MyLoadListener implements LoadEventListener {
|
||||
// this is the single method defined by the LoadEventListener interface
|
||||
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
|
||||
throws HibernateException {
|
||||
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
|
||||
throw MySecurityException("Unauthorized access");
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
デフォルトリスナ以外のリスナを使うには、Hibernateへの設定も必要です:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-configuration>
|
||||
<session-factory>
|
||||
...
|
||||
<event type="load">
|
||||
<listener class="com.eg.MyLoadListener"/>
|
||||
<listener class="org.hibernate.event.def.DefaultLoadEventListener"/>
|
||||
</event>
|
||||
</session-factory>
|
||||
</hibernate-configuration>]]></programlisting>
|
||||
|
||||
<para>
|
||||
またその他に、プログラムで登録する方法もあります:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = new Configuration();
|
||||
LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() };
|
||||
cfg.EventListeners().setLoadEventListeners(stack);]]></programlisting>
|
||||
|
||||
<para>
|
||||
リスナを宣言的に登録すると、そのリスナのインスタンスを共有できません。
|
||||
複数の <literal><listener/></literal> 要素で同じクラス名が使われると、
|
||||
それぞれの参照はそのクラスの別々のインスタンスを指すことになります。
|
||||
リスナ型の間でリスナインスタンスを共有する必要があれば、
|
||||
プログラムで登録する方法を採らなければなりません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
なぜインターフェイスを実装して、特化した型を設定時に指定するのでしょうか?
|
||||
リスナの実装クラスに、複数のイベントリスナインターフェイスを実装できるからです。
|
||||
登録時に追加で型を指定することで、カスタムリスナのon/offを設定時に簡単に切り替えられます。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="objectstate-decl-security" revision="2">
|
||||
<title>Hibernateの宣言的なセキュリティ</title>
|
||||
<para>
|
||||
一般的にHibernateアプリケーションの宣言的なセキュリティは、セッションファサード層で管理します。
|
||||
現在、Hiberenate3はJACCで許可しかつ、JAASで認証したアクションを許しています。
|
||||
これはイベントアーキテクチャの最上位に組み込まれているオプションの機能です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
まず最初に、適切なイベントリスナを設定してJAAS認証を使えるようにしなければなりません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
|
||||
<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
|
||||
<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
|
||||
<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
特定のイベント型に対してちょうど一つのリスナがあるとき、
|
||||
<literal><listener type="..." class="..."/></literal>
|
||||
は <literal><event type="..."><listener class="..."/></event></literal>
|
||||
の簡略形に過ぎないことに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
次に、同じく <literal>hibernate.cfg.xml</literal> でロールにパーミッションを与えてください:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
|
||||
<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
このロール名は使用するJACCプロバイダに理解されるロールです。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,657 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="example-mappings">
|
||||
<title>例:いろいろなマッピング</title>
|
||||
|
||||
<para>
|
||||
この章では、より複雑な関連のマッピングをいくつか紹介します。
|
||||
</para>
|
||||
|
||||
<sect1 id="example-mappings-emp">
|
||||
<title>雇用者/従業員</title>
|
||||
|
||||
<para>
|
||||
<literal>Employer</literal> と <literal>Employee</literal> の関係を表す以下のモデルは、
|
||||
関連の表現に実際のエンティティクラス( <literal>Employment</literal> )
|
||||
を使います。
|
||||
なぜなら、同じ2つのパーティに複数の期間雇用されるということがありえるからです。
|
||||
お金の値と従業員の名前をモデル化するためにコンポーネントを使っています。
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/EmployerEmployee.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/EmployerEmployee.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
マッピングドキュメントの一例です:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Employer" table="employers">
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employer_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
</class>
|
||||
|
||||
<class name="Employment" table="employment_periods">
|
||||
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employment_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="startDate" column="start_date"/>
|
||||
<property name="endDate" column="end_date"/>
|
||||
|
||||
<component name="hourlyRate" class="MonetaryAmount">
|
||||
<property name="amount">
|
||||
<column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
|
||||
</property>
|
||||
<property name="currency" length="12"/>
|
||||
</component>
|
||||
|
||||
<many-to-one name="employer" column="employer_id" not-null="true"/>
|
||||
<many-to-one name="employee" column="employee_id" not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Employee" table="employees">
|
||||
<id name="id">
|
||||
<generator class="sequence">
|
||||
<param name="sequence">employee_id_seq</param>
|
||||
</generator>
|
||||
</id>
|
||||
<property name="taxfileNumber"/>
|
||||
<component name="name" class="Name">
|
||||
<property name="firstName"/>
|
||||
<property name="initial"/>
|
||||
<property name="lastName"/>
|
||||
</component>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>SchemaExport</literal> で生成したテーブルスキーマです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table employers (
|
||||
id BIGINT not null,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table employment_periods (
|
||||
id BIGINT not null,
|
||||
hourly_rate NUMERIC(12, 2),
|
||||
currency VARCHAR(12),
|
||||
employee_id BIGINT not null,
|
||||
employer_id BIGINT not null,
|
||||
end_date TIMESTAMP,
|
||||
start_date TIMESTAMP,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table employees (
|
||||
id BIGINT not null,
|
||||
firstName VARCHAR(255),
|
||||
initial CHAR(1),
|
||||
lastName VARCHAR(255),
|
||||
taxfileNumber VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table employment_periods
|
||||
add constraint employment_periodsFK0 foreign key (employer_id) references employers
|
||||
alter table employment_periods
|
||||
add constraint employment_periodsFK1 foreign key (employee_id) references employees
|
||||
create sequence employee_id_seq
|
||||
create sequence employment_id_seq
|
||||
create sequence employer_id_seq]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-mappings-authorwork">
|
||||
<title>作者/作品</title>
|
||||
|
||||
<para>
|
||||
<literal>Work</literal> , <literal>Author</literal> そして <literal>Person</literal>
|
||||
の関係を表す以下のモデルを考えてみてください。
|
||||
<literal>Work</literal> と <literal>Author</literal> の関係を多対多関連で表しています。
|
||||
<literal>Author</literal> と <literal>Person</literal> の関係は一対一関連として表しています。
|
||||
他には <literal>Author</literal> が <literal>Person</literal> を拡張するという方法もあります。
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
以下のマッピングドキュメントはこのような関係を正確に表現しています。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Work" table="works" discriminator-value="W">
|
||||
|
||||
<id name="id" column="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="type" type="character"/>
|
||||
|
||||
<property name="title"/>
|
||||
<set name="authors" table="author_work">
|
||||
<key column name="work_id"/>
|
||||
<many-to-many class="Author" column name="author_id"/>
|
||||
</set>
|
||||
|
||||
<subclass name="Book" discriminator-value="B">
|
||||
<property name="text"/>
|
||||
</subclass>
|
||||
|
||||
<subclass name="Song" discriminator-value="S">
|
||||
<property name="tempo"/>
|
||||
<property name="genre"/>
|
||||
</subclass>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Author" table="authors">
|
||||
|
||||
<id name="id" column="id">
|
||||
<!-- The Author must have the same identifier as the Person -->
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="alias"/>
|
||||
<one-to-one name="person" constrained="true"/>
|
||||
|
||||
<set name="works" table="author_work" inverse="true">
|
||||
<key column="author_id"/>
|
||||
<many-to-many class="Work" column="work_id"/>
|
||||
</set>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Person" table="persons">
|
||||
<id name="id" column="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
このマッピングには4つのテーブルがあります。
|
||||
<literal>works</literal> , <literal>authors</literal> , <literal>persons</literal>
|
||||
はそれぞれ、仕事、作者、人のデータを保持します。
|
||||
<literal>author_work</literal> は作者と作品をリンクする関連テーブルです。
|
||||
以下は <literal>SchemaExport</literal> で生成したテーブルスキーマです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table works (
|
||||
id BIGINT not null generated by default as identity,
|
||||
tempo FLOAT,
|
||||
genre VARCHAR(255),
|
||||
text INTEGER,
|
||||
title VARCHAR(255),
|
||||
type CHAR(1) not null,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table author_work (
|
||||
author_id BIGINT not null,
|
||||
work_id BIGINT not null,
|
||||
primary key (work_id, author_id)
|
||||
)
|
||||
|
||||
create table authors (
|
||||
id BIGINT not null generated by default as identity,
|
||||
alias VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table persons (
|
||||
id BIGINT not null generated by default as identity,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table authors
|
||||
add constraint authorsFK0 foreign key (id) references persons
|
||||
alter table author_work
|
||||
add constraint author_workFK0 foreign key (author_id) references authors
|
||||
alter table author_work
|
||||
add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-mappings-customerorderproduct">
|
||||
<title>顧客/注文/製品</title>
|
||||
|
||||
<para>
|
||||
さて、 <literal>Customer</literal> , <literal>Order</literal> , <literal>LineItem</literal>
|
||||
<literal>Product</literal> の関係を表すモデルを考えてみましょう。
|
||||
<literal>Customer</literal> と <literal>Order</literal> は一対多の関連ですが、
|
||||
<literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>
|
||||
はどのように表現するべきでしょうか?
|
||||
<literal>LineItem</literal> を、<literal>Order</literal> と <literal>Product</literal>
|
||||
の多対多関連を表現する関連クラスとしてマッピングしました。
|
||||
Hibernateではこれをコンポジット要素と呼びます。
|
||||
</para>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<para>
|
||||
マッピングドキュメント:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class name="Customer" table="customers">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name"/>
|
||||
<set name="orders" inverse="true">
|
||||
<key column="customer_id"/>
|
||||
<one-to-many class="Order"/>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Order" table="orders">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="date"/>
|
||||
<many-to-one name="customer" column="customer_id"/>
|
||||
<list name="lineItems" table="line_items">
|
||||
<key column="order_id"/>
|
||||
<list-index column="line_number"/>
|
||||
<composite-element class="LineItem">
|
||||
<property name="quantity"/>
|
||||
<many-to-one name="product" column="product_id"/>
|
||||
</composite-element>
|
||||
</list>
|
||||
</class>
|
||||
|
||||
<class name="Product" table="products">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="serialNumber"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>customers</literal> , <literal>orders</literal> , <literal>line_items</literal> ,
|
||||
<literal>products</literal> はそれぞれ、顧客、注文、注文明細、製品のデータを保持します。
|
||||
<literal>line_items</literal> は注文と製品をリンクする関連テーブルとしても働きます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[create table customers (
|
||||
id BIGINT not null generated by default as identity,
|
||||
name VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table orders (
|
||||
id BIGINT not null generated by default as identity,
|
||||
customer_id BIGINT,
|
||||
date TIMESTAMP,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table line_items (
|
||||
line_number INTEGER not null,
|
||||
order_id BIGINT not null,
|
||||
product_id BIGINT,
|
||||
quantity INTEGER,
|
||||
primary key (order_id, line_number)
|
||||
)
|
||||
|
||||
create table products (
|
||||
id BIGINT not null generated by default as identity,
|
||||
serialNumber VARCHAR(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table orders
|
||||
add constraint ordersFK0 foreign key (customer_id) references customers
|
||||
alter table line_items
|
||||
add constraint line_itemsFK0 foreign key (product_id) references products
|
||||
alter table line_items
|
||||
add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="misc">
|
||||
<title>種々雑多なマッピング例</title>
|
||||
|
||||
<para>
|
||||
ここにある例はすべてHibernateのテストスイートから取りました。
|
||||
そこには、他にもたくさんのマッピングの例があります。
|
||||
Hibernateディストリビューションの <literal>test</literal> フォルダを見てください。
|
||||
</para>
|
||||
|
||||
<para>TODO: ここに文章を埋める</para>
|
||||
|
||||
<sect2 id="example-mappings-typed-onetone">
|
||||
<title>「型付けされた」一対一関連</title>
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="name"/>
|
||||
<one-to-one name="address"
|
||||
cascade="all">
|
||||
<formula>name</formula>
|
||||
<formula>'HOME'</formula>
|
||||
</one-to-one>
|
||||
<one-to-one name="mailingAddress"
|
||||
cascade="all">
|
||||
<formula>name</formula>
|
||||
<formula>'MAILING'</formula>
|
||||
</one-to-one>
|
||||
</class>
|
||||
|
||||
<class name="Address" batch-size="2"
|
||||
check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
|
||||
<composite-id>
|
||||
<key-many-to-one name="person"
|
||||
column="personName"/>
|
||||
<key-property name="type"
|
||||
column="addressType"/>
|
||||
</composite-id>
|
||||
<property name="street" type="text"/>
|
||||
<property name="state"/>
|
||||
<property name="zip"/>
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key">
|
||||
<title>複合キーの例</title>
|
||||
<programlisting><![CDATA[<class name="Customer">
|
||||
|
||||
<id name="customerId"
|
||||
length="10">
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="name" not-null="true" length="100"/>
|
||||
<property name="address" not-null="true" length="200"/>
|
||||
|
||||
<list name="orders"
|
||||
inverse="true"
|
||||
cascade="save-update">
|
||||
<key column="customerId"/>
|
||||
<index column="orderNumber"/>
|
||||
<one-to-many class="Order"/>
|
||||
</list>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Order" table="CustomerOrder" lazy="true">
|
||||
<synchronize table="LineItem"/>
|
||||
<synchronize table="Product"/>
|
||||
|
||||
<composite-id name="id"
|
||||
class="Order$Id">
|
||||
<key-property name="customerId" length="10"/>
|
||||
<key-property name="orderNumber"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="orderDate"
|
||||
type="calendar_date"
|
||||
not-null="true"/>
|
||||
|
||||
<property name="total">
|
||||
<formula>
|
||||
( select sum(li.quantity*p.price)
|
||||
from LineItem li, Product p
|
||||
where li.productId = p.productId
|
||||
and li.customerId = customerId
|
||||
and li.orderNumber = orderNumber )
|
||||
</formula>
|
||||
</property>
|
||||
|
||||
<many-to-one name="customer"
|
||||
column="customerId"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true"/>
|
||||
|
||||
<bag name="lineItems"
|
||||
fetch="join"
|
||||
inverse="true"
|
||||
cascade="save-update">
|
||||
<key>
|
||||
<column name="customerId"/>
|
||||
<column name="orderNumber"/>
|
||||
</key>
|
||||
<one-to-many class="LineItem"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="LineItem">
|
||||
|
||||
<composite-id name="id"
|
||||
class="LineItem$Id">
|
||||
<key-property name="customerId" length="10"/>
|
||||
<key-property name="orderNumber"/>
|
||||
<key-property name="productId" length="10"/>
|
||||
</composite-id>
|
||||
|
||||
<property name="quantity"/>
|
||||
|
||||
<many-to-one name="order"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true">
|
||||
<column name="customerId"/>
|
||||
<column name="orderNumber"/>
|
||||
</many-to-one>
|
||||
|
||||
<many-to-one name="product"
|
||||
insert="false"
|
||||
update="false"
|
||||
not-null="true"
|
||||
column="productId"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Product">
|
||||
<synchronize table="LineItem"/>
|
||||
|
||||
<id name="productId"
|
||||
length="10">
|
||||
<generator class="assigned"/>
|
||||
</id>
|
||||
|
||||
<property name="description"
|
||||
not-null="true"
|
||||
length="200"/>
|
||||
<property name="price" length="3"/>
|
||||
<property name="numberAvailable"/>
|
||||
|
||||
<property name="numberOrdered">
|
||||
<formula>
|
||||
( select sum(li.quantity)
|
||||
from LineItem li
|
||||
where li.productId = productId )
|
||||
</formula>
|
||||
</property>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-composite-key-manytomany">
|
||||
<title>複合キー属性を共有する多対多</title>
|
||||
<programlisting><![CDATA[<class name="User" table="`User`">
|
||||
<composite-id>
|
||||
<key-property name="name"/>
|
||||
<key-property name="org"/>
|
||||
</composite-id>
|
||||
<set name="groups" table="UserGroup">
|
||||
<key>
|
||||
<column name="userName"/>
|
||||
<column name="org"/>
|
||||
</key>
|
||||
<many-to-many class="Group">
|
||||
<column name="groupName"/>
|
||||
<formula>org</formula>
|
||||
</many-to-many>
|
||||
</set>
|
||||
</class>
|
||||
|
||||
<class name="Group" table="`Group`">
|
||||
<composite-id>
|
||||
<key-property name="name"/>
|
||||
<key-property name="org"/>
|
||||
</composite-id>
|
||||
<property name="description"/>
|
||||
<set name="users" table="UserGroup" inverse="true">
|
||||
<key>
|
||||
<column name="groupName"/>
|
||||
<column name="org"/>
|
||||
</key>
|
||||
<many-to-many class="User">
|
||||
<column name="userName"/>
|
||||
<formula>org</formula>
|
||||
</many-to-many>
|
||||
</set>
|
||||
</class>
|
||||
]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-content-discrimination">
|
||||
<title>discriminationに基づく内容</title>
|
||||
<programlisting><![CDATA[<class name="Person"
|
||||
discriminator-value="P">
|
||||
|
||||
<id name="id"
|
||||
column="person_id"
|
||||
unsaved-value="0">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
|
||||
<discriminator
|
||||
type="character">
|
||||
<formula>
|
||||
case
|
||||
when title is not null then 'E'
|
||||
when salesperson is not null then 'C'
|
||||
else 'P'
|
||||
end
|
||||
</formula>
|
||||
</discriminator>
|
||||
|
||||
<property name="name"
|
||||
not-null="true"
|
||||
length="80"/>
|
||||
|
||||
<property name="sex"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
|
||||
<component name="address">
|
||||
<property name="address"/>
|
||||
<property name="zip"/>
|
||||
<property name="country"/>
|
||||
</component>
|
||||
|
||||
<subclass name="Employee"
|
||||
discriminator-value="E">
|
||||
<property name="title"
|
||||
length="20"/>
|
||||
<property name="salary"/>
|
||||
<many-to-one name="manager"/>
|
||||
</subclass>
|
||||
|
||||
<subclass name="Customer"
|
||||
discriminator-value="C">
|
||||
<property name="comments"/>
|
||||
<many-to-one name="salesperson"/>
|
||||
</subclass>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="example-mappings-association-alternatekeys" revision="2">
|
||||
<title>代替キーの関連</title>
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
|
||||
<id name="id">
|
||||
<generator class="hilo"/>
|
||||
</id>
|
||||
|
||||
<property name="name" length="100"/>
|
||||
|
||||
<one-to-one name="address"
|
||||
property-ref="person"
|
||||
cascade="all"
|
||||
fetch="join"/>
|
||||
|
||||
<set name="accounts"
|
||||
inverse="true">
|
||||
<key column="userId"
|
||||
property-ref="userId"/>
|
||||
<one-to-many class="Account"/>
|
||||
</set>
|
||||
|
||||
<property name="userId" length="8"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Address">
|
||||
|
||||
<id name="id">
|
||||
<generator class="hilo"/>
|
||||
</id>
|
||||
|
||||
<property name="address" length="300"/>
|
||||
<property name="zip" length="5"/>
|
||||
<property name="country" length="25"/>
|
||||
<many-to-one name="person" unique="true" not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Account">
|
||||
<id name="accountId" length="32">
|
||||
<generator class="uuid"/>
|
||||
</id>
|
||||
|
||||
<many-to-one name="user"
|
||||
column="userId"
|
||||
property-ref="userId"/>
|
||||
|
||||
<property name="type" not-null="true"/>
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="example-parentchild">
|
||||
<title>例:親/子供
|
||||
</title>
|
||||
|
||||
<para>
|
||||
新規ユーザがHibernateを使ってまず最初に扱うモデルの一つに、親子型のモデル化があります。
|
||||
このモデル化には二つのアプローチが存在します。とりわけ新規ユーザにとって、
|
||||
さまざまな理由から最も便利だと思われるアプローチは、<literal>親</literal> から <literal>子供</literal>
|
||||
への <literal><one-to-many></literal> 関連により <literal>親</literal> と <literal>子供</literal>
|
||||
の両方をエンティティクラスとしてモデリングする方法です
|
||||
(もう一つの方法は、<literal>子供</literal> を <literal><composite-element></literal> として定義するものです)。
|
||||
これで(Hibernateにおける)一対多関連のデフォルトのセマンティクスが、通常の複合要素のマッピングよりも、
|
||||
親子関係のセマンティクスから遠いことがわかります。
|
||||
それでは親子関係を効率的かつエレガントにモデリングするために、
|
||||
<emphasis>カスケード操作を使った双方向一対多関連</emphasis> の扱い方を説明します。これはまったく難しいものではありません。
|
||||
|
||||
</para>
|
||||
|
||||
<sect1 id="example-parentchild-collections">
|
||||
<title>コレクションに関する注意</title>
|
||||
|
||||
<para>
|
||||
Hibernateのコレクションは自身のエンティティの論理的な部分と考えられ、
|
||||
決して包含するエンティティのものではありません。これは致命的な違いです!
|
||||
これは以下のような結果になります:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
オブジェクトをコレクションから削除、またはコレクションに追加するとき、
|
||||
コレクションのオーナーのバージョン番号はインクリメントされます。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
もしコレクションから削除されたオブジェクトが値型のインスタンス
|
||||
(例えばコンポジットエレメント)だったならば、そのオブジェクトは永続的ではなくなり、
|
||||
その状態はデータベースから完全に削除されます。
|
||||
同じように、値型のインスタンスをコレクションに追加すると、その状態はすぐに永続的になります。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
一方、もしエンティティがコレクション(一対多または多対多関連)から削除されても、
|
||||
デフォルトではそれは削除されません。この動作は完全に一貫しています。
|
||||
すなわち、他のエンティティの内部状態を変更しても、関連するエンティティが消滅すべきではないということです。
|
||||
同様に、エンティティがコレクションに追加されても、デフォルトではそのエンティティは永続的にはなりません。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
その代わりに、デフォルトの動作では、エンティティをコレクションに追加すると単に二つのエンティティ間のリンクを作成し、
|
||||
一方エンティティを削除するとリンクも削除します。これはすべてのケースにおいて非常に適切です。
|
||||
これが適切でないのは親/子関係の場合です。この場合子供の生存は親のライフサイクルに制限されるからです。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-bidir">
|
||||
<title>双方向一対多
|
||||
</title>
|
||||
|
||||
<para>
|
||||
<literal>Parent</literal> から <literal>Child</literal> への単純な <literal><one-to-many></literal> 関連から始めるとします。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
以下のコードを実行すると、
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = .....;
|
||||
Child c = new Child();
|
||||
p.getChildren().add(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Hibernateは二つのSQL文を発行します:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>c</literal>に対するレコードを生成する<literal>INSERT</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>p</literal>から<literal>c</literal>へのリンクを作成する<literal>UPDATE</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
これは非効率的なだけではなく、<literal>parent_id</literal> カラムにおいて <literal>NOT NULL</literal> 制約に違反します。
|
||||
コレクションのマッピングで <literal>not-null="true"</literal> と指定することで、null制約違反を解決することができます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children">
|
||||
<key column="parent_id" not-null="true"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
しかしこの解決策は推奨できません。
|
||||
</para>
|
||||
<para>
|
||||
この動作の根本的な原因は、<literal>p</literal> から <literal>c</literal> へのリンク
|
||||
(外部キー <literal>parent_id</literal>)は <literal>Child</literal> オブジェクトの状態の一部とは考えられず、
|
||||
そのため <literal>INSERT</literal> によってリンクが生成されないことです。
|
||||
ですから、解決策はリンクをChildマッピングの一部にすることです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
(また <literal>Child</literal> クラスに <literal>parent</literal> プロパティを追加する必要があります。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
それでは <literal>Child</literal> エンティティがリンクの状態を制御するようになったので、
|
||||
コレクションがリンクを更新しないようにしましょう。それには <literal>inverse</literal> 属性を使います。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
以下のコードを使えば、新しい <literal>Child</literal> を追加することができます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
c.setParent(p);
|
||||
p.getChildren().add(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
これにより、SQLの <literal>INSERT</literal> 文が一つだけが発行されるようになりました!
|
||||
</para>
|
||||
|
||||
<para>
|
||||
もう少し強化するには、<literal>Parent</literal> の <literal>addChild()</literal> メソッドを作成します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public void addChild(Child c) {
|
||||
c.setParent(this);
|
||||
children.add(c);
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Child</literal> を追加するコードはこのようになります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
p.addChild(c);
|
||||
session.save(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-cascades">
|
||||
<title>ライフサイクルのカスケード</title>
|
||||
|
||||
<para>
|
||||
明示的に <literal>save()</literal> をコールするのはまだ煩わしいものです。これをカスケードを使って対処します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
これにより先ほどのコードをこのように単純化します
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = new Child();
|
||||
p.addChild(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
同様に <literal>Parent</literal> を保存または削除するときに、子供を一つ一つ取り出して扱う必要はありません。
|
||||
以下のコードは <literal>p</literal> を削除し、そしてデータベースからその子供をすべて削除します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
session.delete(p);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
しかしこのコードは
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = (Child) p.getChildren().iterator().next();
|
||||
p.getChildren().remove(c);
|
||||
c.setParent(null);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
データベースから <literal>c</literal> を削除しません。<literal>p</literal> へのリンクを削除する
|
||||
(そしてこのケースでは <literal>NOT NULL</literal> 制約違反を引き起こす)だけです。
|
||||
<literal>Child</literal> の <literal>delete()</literal> を明示する必要があります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
|
||||
Child c = (Child) p.getChildren().iterator().next();
|
||||
p.getChildren().remove(c);
|
||||
session.delete(c);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
今このケースでは実際に <literal>Child</literal> が親なしでは存在できないようになりました。
|
||||
そのため、もしコレクションから <literal>Child</literal> を取り除く場合、これも削除したいです。
|
||||
そのためには <literal>cascade="all-delete-orphan"</literal> を使わなければなりません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
|
||||
<key column="parent_id"/>
|
||||
<one-to-many class="Child"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
注意:コレクションのマッピングで <literal>inverse="true"</literal> と指定しても、
|
||||
コレクションの要素のイテレーションによって、依然カスケードが実行されます。
|
||||
そのためもしカスケードでオブジェクトをセーブ、削除、更新する必要があるなら、
|
||||
それをコレクションに追加しなければなりません。単に <literal>setParent()</literal> を呼ぶだけでは不十分です。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-update">
|
||||
<title>カスケードと <literal>unsaved-value</literal></title>
|
||||
|
||||
<para>
|
||||
<literal>Parent</literal> が、ある <literal>Session</literal> でロードされ、UIのアクションで変更が加えられ、
|
||||
<literal>update()</literal> を呼んでこの変更を新しいセッションで永続化したいとします。
|
||||
<literal>Parent</literal> が子供のコレクションを持ち、カスケード更新が有効になっているため、
|
||||
Hibernateはどの子供が新しくインスタンス化されたか、どれがデータベースの既存の行に相当するのかを知る必要があります。
|
||||
<literal>Parent</literal> と <literal>Child</literal> の両方が <literal>java.lang.Long</literal>
|
||||
型の識別プロパティを生成したとしましょう。
|
||||
Hibernateはどの子供が新しいものかを決定するために識別プロパティの値を使います(versionやtimestampプロパティも使えます。
|
||||
<xref linkend="manipulatingdata-updating-detached"/> 参照)。Hibernate3になって、
|
||||
明示的に <literal>unsaved-value</literal> を指定する必要はなくなりました。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
以下のコードは <literal>parent</literal> と <literal>child</literal> を更新し、<literal>newChild</literal> を挿入します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[//parent and child were both loaded in a previous session
|
||||
//parentとchildは両方とも、以前のSessionでロードされています
|
||||
parent.addChild(child);
|
||||
Child newChild = new Child();
|
||||
parent.addChild(newChild);
|
||||
session.update(parent);
|
||||
session.flush();]]></programlisting>
|
||||
|
||||
<para>
|
||||
これらは生成された識別子の場合には非常に良いのですが、割り当てられた識別子と複合識別子の場合はどうでしょうか?
|
||||
これはHibernateが、(ユーザにより割り当てられた識別子を持つ)新しくインスタンス化されたオブジェクトと、
|
||||
以前のSessionでロードされたオブジェクトを区別できないため、より難しいです。
|
||||
この場合、Hibernateはタイムスタンプかバージョンのプロパティのどちらかを使うか、二次キャッシュに問い合わせます。
|
||||
最悪の場合、行が存在するかどうかデータベースを見ます。
|
||||
</para>
|
||||
|
||||
<!-- undocumenting
|
||||
<para>
|
||||
There is one further possibility. The <literal>Interceptor</literal> method named
|
||||
<literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
|
||||
newly instantiated objects. For example, you could define a base class for your persistent classes.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Persistent {
|
||||
private boolean _saved = false;
|
||||
public void onSave() {
|
||||
_saved=true;
|
||||
}
|
||||
public void onLoad() {
|
||||
_saved=true;
|
||||
}
|
||||
......
|
||||
public boolean isSaved() {
|
||||
return _saved;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
(The <literal>saved</literal> property is non-persistent.)
|
||||
Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
|
||||
and <literal>onSave()</literal> as follows.
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
|
||||
if (entity instanceof Persistent) {
|
||||
return new Boolean( !( (Persistent) entity ).isSaved() );
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onLoad(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onSave(Object entity,
|
||||
Serializable id,
|
||||
Object[] state,
|
||||
String[] propertyNames,
|
||||
Type[] types) {
|
||||
|
||||
if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
|
||||
return false;
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
|
||||
</para>
|
||||
-->
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-parentchild-conclusion">
|
||||
<title>結論
|
||||
</title>
|
||||
|
||||
<para>
|
||||
ここではかなりの量を要約したので、最初の頃は混乱しているように思われるかもしれません。
|
||||
しかし実際は、すべて非常に良く動作します。ほとんどのHibernateアプリケーションでは、多くの場面で親子パターンを使用します。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
最初の段落で代替方法について触れました。上記のような問題は <literal><composite-element></literal> マッピングの場合は存在せず、
|
||||
にもかかわらずそれは確かに親子関係のセマンティクスを持ちます。
|
||||
しかし残念ながら、複合要素クラスには二つの大きな制限があります:
|
||||
1つは複合要素はコレクションを持つことができないことです。もうひとつは、
|
||||
ユニークな親ではないエンティティの子供となるべきではないということです
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,433 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="example-weblog">
|
||||
<title>例: Weblogアプリケーション</title>
|
||||
|
||||
<sect1 id="example-weblog-classes">
|
||||
<title>永続クラス
|
||||
</title>
|
||||
|
||||
<para>
|
||||
永続クラスがウェブログと、ウェブログに掲示された項目を表しています。
|
||||
それらは通常の親子関係としてモデリングされますが、
|
||||
setではなく順序を持ったbagを使用することにします。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Blog {
|
||||
private Long _id;
|
||||
private String _name;
|
||||
private List _items;
|
||||
|
||||
public Long getId() {
|
||||
return _id;
|
||||
}
|
||||
public List getItems() {
|
||||
return _items;
|
||||
}
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
public void setId(Long long1) {
|
||||
_id = long1;
|
||||
}
|
||||
public void setItems(List list) {
|
||||
_items = list;
|
||||
}
|
||||
public void setName(String string) {
|
||||
_name = string;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class BlogItem {
|
||||
private Long _id;
|
||||
private Calendar _datetime;
|
||||
private String _text;
|
||||
private String _title;
|
||||
private Blog _blog;
|
||||
|
||||
public Blog getBlog() {
|
||||
return _blog;
|
||||
}
|
||||
public Calendar getDatetime() {
|
||||
return _datetime;
|
||||
}
|
||||
public Long getId() {
|
||||
return _id;
|
||||
}
|
||||
public String getText() {
|
||||
return _text;
|
||||
}
|
||||
public String getTitle() {
|
||||
return _title;
|
||||
}
|
||||
public void setBlog(Blog blog) {
|
||||
_blog = blog;
|
||||
}
|
||||
public void setDatetime(Calendar calendar) {
|
||||
_datetime = calendar;
|
||||
}
|
||||
public void setId(Long long1) {
|
||||
_id = long1;
|
||||
}
|
||||
public void setText(String string) {
|
||||
_text = string;
|
||||
}
|
||||
public void setTitle(String string) {
|
||||
_title = string;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-weblog-mappings">
|
||||
<title>Hibernateのマッピング
|
||||
</title>
|
||||
|
||||
<para>
|
||||
XMLマッピングは、今ではとても簡単なはずです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="eg">
|
||||
|
||||
<class
|
||||
name="Blog"
|
||||
table="BLOGS">
|
||||
|
||||
<id
|
||||
name="id"
|
||||
column="BLOG_ID">
|
||||
|
||||
<generator class="native"/>
|
||||
|
||||
</id>
|
||||
|
||||
<property
|
||||
name="name"
|
||||
column="NAME"
|
||||
not-null="true"
|
||||
unique="true"/>
|
||||
|
||||
<bag
|
||||
name="items"
|
||||
inverse="true"
|
||||
order-by="DATE_TIME"
|
||||
cascade="all">
|
||||
|
||||
<key column="BLOG_ID"/>
|
||||
<one-to-many class="BlogItem"/>
|
||||
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="eg">
|
||||
|
||||
<class
|
||||
name="BlogItem"
|
||||
table="BLOG_ITEMS"
|
||||
dynamic-update="true">
|
||||
|
||||
<id
|
||||
name="id"
|
||||
column="BLOG_ITEM_ID">
|
||||
|
||||
<generator class="native"/>
|
||||
|
||||
</id>
|
||||
|
||||
<property
|
||||
name="title"
|
||||
column="TITLE"
|
||||
not-null="true"/>
|
||||
|
||||
<property
|
||||
name="text"
|
||||
column="TEXT"
|
||||
not-null="true"/>
|
||||
|
||||
<property
|
||||
name="datetime"
|
||||
column="DATE_TIME"
|
||||
not-null="true"/>
|
||||
|
||||
<many-to-one
|
||||
name="blog"
|
||||
column="BLOG_ID"
|
||||
not-null="true"/>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="example-weblog-code">
|
||||
<title>Hibernateのコード</title>
|
||||
|
||||
<para>
|
||||
以下のクラスは、
|
||||
Hibernateでこれらのクラスを使ってできることをいくつか示しています。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
|
||||
public class BlogMain {
|
||||
|
||||
private SessionFactory _sessions;
|
||||
|
||||
public void configure() throws HibernateException {
|
||||
_sessions = new Configuration()
|
||||
.addClass(Blog.class)
|
||||
.addClass(BlogItem.class)
|
||||
.buildSessionFactory();
|
||||
}
|
||||
|
||||
public void exportTables() throws HibernateException {
|
||||
Configuration cfg = new Configuration()
|
||||
.addClass(Blog.class)
|
||||
.addClass(BlogItem.class);
|
||||
new SchemaExport(cfg).create(true, true);
|
||||
}
|
||||
|
||||
public Blog createBlog(String name) throws HibernateException {
|
||||
|
||||
Blog blog = new Blog();
|
||||
blog.setName(name);
|
||||
blog.setItems( new ArrayList() );
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.persist(blog);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return blog;
|
||||
}
|
||||
|
||||
public BlogItem createBlogItem(Blog blog, String title, String text)
|
||||
throws HibernateException {
|
||||
|
||||
BlogItem item = new BlogItem();
|
||||
item.setTitle(title);
|
||||
item.setText(text);
|
||||
item.setBlog(blog);
|
||||
item.setDatetime( Calendar.getInstance() );
|
||||
blog.getItems().add(item);
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.update(blog);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public BlogItem createBlogItem(Long blogid, String title, String text)
|
||||
throws HibernateException {
|
||||
|
||||
BlogItem item = new BlogItem();
|
||||
item.setTitle(title);
|
||||
item.setText(text);
|
||||
item.setDatetime( Calendar.getInstance() );
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Blog blog = (Blog) session.load(Blog.class, blogid);
|
||||
item.setBlog(blog);
|
||||
blog.getItems().add(item);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public void updateBlogItem(BlogItem item, String text)
|
||||
throws HibernateException {
|
||||
|
||||
item.setText(text);
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
session.update(item);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBlogItem(Long itemid, String text)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
|
||||
item.setText(text);
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
public List listAllBlogNamesAndItemCounts(int max)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
List result = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"select blog.id, blog.name, count(blogItem) " +
|
||||
"from Blog as blog " +
|
||||
"left outer join blog.items as blogItem " +
|
||||
"group by blog.name, blog.id " +
|
||||
"order by max(blogItem.datetime)"
|
||||
);
|
||||
q.setMaxResults(max);
|
||||
result = q.list();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Blog getBlogAndAllItems(Long blogid)
|
||||
throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
Blog blog = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"from Blog as blog " +
|
||||
"left outer join fetch blog.items " +
|
||||
"where blog.id = :blogid"
|
||||
);
|
||||
q.setParameter("blogid", blogid);
|
||||
blog = (Blog) q.uniqueResult();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return blog;
|
||||
}
|
||||
|
||||
public List listBlogsAndRecentItems() throws HibernateException {
|
||||
|
||||
Session session = _sessions.openSession();
|
||||
Transaction tx = null;
|
||||
List result = null;
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
Query q = session.createQuery(
|
||||
"from Blog as blog " +
|
||||
"inner join blog.items as blogItem " +
|
||||
"where blogItem.datetime > :minDate"
|
||||
);
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.roll(Calendar.MONTH, false);
|
||||
q.setCalendar("minDate", cal);
|
||||
|
||||
result = q.list();
|
||||
tx.commit();
|
||||
}
|
||||
catch (HibernateException he) {
|
||||
if (tx!=null) tx.rollback();
|
||||
throw he;
|
||||
}
|
||||
finally {
|
||||
session.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="filters">
|
||||
<title>データのフィルタリング</title>
|
||||
|
||||
<para>
|
||||
Hibernate3では「可視性」ルールに基づいてデータを扱うための画期的な方法を用意しています。
|
||||
<emphasis>Hibernate filter</emphasis> はグローバルで、名前付きで、パラメータ化されたフィルタです。
|
||||
これはHibernateセッションごとに有効無効を切り替えられます。
|
||||
</para>
|
||||
|
||||
<sect1 id="objectstate-filters">
|
||||
<title>Hibernateのフィルタ</title>
|
||||
|
||||
<para>
|
||||
Hibernate3はフィルタクライテリアをあらかじめ定義し、
|
||||
これらのフィルタをクラスやコレクションレベルに加える機能を加えました。
|
||||
フィルタクライテリアは制約節を定義する機能です。
|
||||
これらのフィルタ条件はパラメータ化できるということを除き、
|
||||
クラスやさまざまなコレクション要素で利用可能な「where」句に非常によく似ています。
|
||||
アプリケーションは、与えられたフィルタを可能にすべきか、
|
||||
そしてそのパラメータ値を何にすべきかを実行時に決定することができます。
|
||||
フィルタはデータベースビューのように使用されますが、アプリケーション内ではパラメータ化されます。
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
フィルタを使うためにはまず、適切なマッピング要素に定義、追加しなくてはなりません。
|
||||
フィルタを定義するためには、
|
||||
<literal><hibernate-mapping/></literal> 要素内で <literal><filter-def/></literal> 要素を使用します。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="myFilter">
|
||||
<filter-param name="myFilterParam" type="string"/>
|
||||
</filter-def>]]></programlisting>
|
||||
|
||||
<para>
|
||||
そうしてフィルタはクラスへと結び付けられます。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="myClass" ...>
|
||||
...
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
また、コレクションに対しては次のようになります。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<set ...>
|
||||
<filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<para>
|
||||
どちらに対しても(また、それぞれを複数)同時に設定することもできます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>Session</literal> 上のメソッドは <literal>enableFilter(String filterName)</literal>,
|
||||
<literal>getEnabledFilter(String filterName)</literal>, <literal>disableFilter(String filterName)</literal> です。
|
||||
デフォルトでは、フィルタは与えられたセッションに対して使用 <emphasis>できません</emphasis> 。
|
||||
<literal>Filter</literal> インスタンスを返り値とする <literal>Session.enabledFilter()</literal> メソッドを使うことで、
|
||||
フィルタは明示的に使用可能となります。
|
||||
上で定義した単純なフィルタの使用は、このようになります。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
|
||||
|
||||
<para>
|
||||
org.hibernate.Filterインターフェイスのメソッドは、
|
||||
Hibernateの多くに共通しているメソッド連鎖を許していることに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
有効なレコードデータパターンを持つ一時データを使った完全な例です:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<filter-def name="effectiveDate">
|
||||
<filter-param name="asOfDate" type="date"/>
|
||||
</filter-def>
|
||||
|
||||
<class name="Employee" ...>
|
||||
...
|
||||
<many-to-one name="department" column="dept_id" class="Department"/>
|
||||
<property name="effectiveStartDate" type="date" column="eff_start_dt"/>
|
||||
<property name="effectiveEndDate" type="date" column="eff_end_dt"/>
|
||||
...
|
||||
<!--
|
||||
Note that this assumes non-terminal records have an eff_end_dt set to
|
||||
a max db date for simplicity-sake
|
||||
|
||||
|
||||
-->
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</class>
|
||||
|
||||
<class name="Department" ...>
|
||||
...
|
||||
<set name="employees" lazy="true">
|
||||
<key column="dept_id"/>
|
||||
<one-to-many class="Employee"/>
|
||||
<filter name="effectiveDate"
|
||||
condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
</set>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
常に現在の有効レコードを返却することを保証するために、
|
||||
単純に、社員データの検索より前にセッション上のフィルタを有効にします。
|
||||
|
||||
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session session = ...;
|
||||
session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
|
||||
List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
|
||||
.setLong("targetSalary", new Long(1000000))
|
||||
.list();
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
上記のHQLでは、結果の給料の制約について明示的に触れただけですが、
|
||||
有効になっているフィルタのおかげで、このクエリは給料が100万ドル以上の現役の社員だけを返します。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
(HQLかロードフェッチで)外部結合を持つフィルタを使うつもりなら、
|
||||
条件式の方向に注意してください。
|
||||
|
||||
これは左外部結合のために設定するのが最も安全です。
|
||||
一般的に、演算子の後カラム名に続けて最初のパラメータを配置してください。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="inheritance">
|
||||
<title>継承マッピング</title>
|
||||
|
||||
<sect1 id="inheritance-strategies" revision="3">
|
||||
<title>3つの戦略</title>
|
||||
|
||||
<para>
|
||||
Hibernateは3つの基本的な継承のマッピング戦略をサポートします。
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
クラス階層ごとのテーブル(table-per-class-hierarchy)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
サブクラスごとのテーブル(table-per-subclass)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
具象クラスごとのテーブル(table-per-concrete-class)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
加えて4つ目に、Hibernateはわずかに異なる性質を持ったポリモーフィズムをサポートします。
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
暗黙的ポリモーフィズム
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
同一の継承階層の異なるブランチに対して異なるマッピング戦略を使うことができます。
|
||||
その場合には全体の階層に渡るポリモーフィズムを実現するために暗黙的ポリモーフィズムを使用します。
|
||||
しかし、Hibernateは同じルート <literal><class></literal> 要素内で
|
||||
<literal><subclass></literal> マッピング、<literal><joined-subclass></literal> マッピング、
|
||||
<literal><union-subclass></literal> マッピングの同時使用をサポートしていません。
|
||||
<literal><subclass></literal> 要素と <literal><join></literal> 要素を組み合わせることで、
|
||||
同一 <literal><class></literal> 要素内での table-per-hierarchy 戦略と
|
||||
table-per-subclass 戦略の同時使用は可能です。次の例を見てください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>subclass</literal>, <literal>union-subclass</literal> と
|
||||
<literal>joined-subclass</literal> マッピングを複数のマッピングドキュメントに定義することが出来、
|
||||
<literal>hibernate-mapping</literal> の直下に配置します。
|
||||
これは新しいマッピングファイルを追加するだけで、クラス階層を拡張できるということです。
|
||||
あらかじめマップしたスーパークラスを指定して、サブクラスマッピングに <literal>extends</literal>
|
||||
属性を記述しなければなりません。
|
||||
注意:この特徴により、以前はマッピング・ドキュメントの順番が重要でした。
|
||||
Hibernate3からは、extendsキーワードを使う場合、マッピングドキュメントの順番は問題になりません。
|
||||
|
||||
1つのマッピングファイル内で順番付けを行うときは、
|
||||
依然として、サブクラスを定義する前にスーパークラスを定義する必要があります。)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<hibernate-mapping>
|
||||
<subclass name="DomesticCat" extends="Cat" discriminator-value="D">
|
||||
<property name="name" type="string"/>
|
||||
</subclass>
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
|
||||
<sect2 id="inheritance-tableperclass" >
|
||||
<title>クラス階層ごとのテーブル(table-per-class-hierarchy)</title>
|
||||
|
||||
<para>
|
||||
例えば、インターフェイス <literal>Payment</literal> と、それを実装した
|
||||
<literal>CreditCardPayment</literal>、<literal>CashPayment</literal>、
|
||||
<literal>ChequePayment</literal> があるとします。階層ごとのテーブルマッピングは
|
||||
以下のようになります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
...
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
ちょうど一つのテーブルが必要です。
|
||||
このマッピング戦略には一つ大きな制限があります。
|
||||
<literal>CCTYPE</literal> のような、サブクラスで宣言されたカラムは <literal>NOT NULL</literal>
|
||||
制約を持てません。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tablepersubclass">
|
||||
<title>サブクラスごとのテーブル(table-per-subclass)</title>
|
||||
|
||||
<para>
|
||||
table-per-subclass マッピングは以下のようになります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
このマッピングには4つのテーブルが必要です。3つのサブクラステーブルは
|
||||
スーパークラステーブルとの関連を示す主キーを持っています
|
||||
(実際、関係モデル上は一対一関連です)。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
|
||||
<title>弁別子を用いた table-per-subclass</title>
|
||||
|
||||
<para>
|
||||
Hibernateの table-per-subclass 実装は、discriminatorカラムを必要としないことを覚えておいてください。
|
||||
Hibernate以外のO/Rマッパーは、table-per-subclass に異なる実装を用います。
|
||||
それは、スーパークラスのテーブルにタイプdiscriminatorカラムを必要とします。
|
||||
このアプローチは実装が困難になりますが、関係の視点から見ると、より正確なものです。
|
||||
table-per-subclass 戦略でdiscriminatorカラムを使いたければ、
|
||||
<literal><subclass></literal> と <literal><join></literal>
|
||||
を以下のように組み合わせて使ってください。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<join table="CREDIT_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
<join table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
<join table="CHEQUE_PAYMENT" fetch="select">
|
||||
<key column="PAYMENT_ID"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
オプションの <literal>fetch="select"</literal> 宣言は、
|
||||
スーパークラスのクエリ実行時に外部結合を使って、
|
||||
サブクラスの <literal>ChequePayment</literal> データを取得しないように指定するためのものです。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
|
||||
<title>table-per-subclass と table-per-class-hierarchy の混合</title>
|
||||
|
||||
<para>
|
||||
このアプローチを使用すると、table-per-hierarchy と table-per-subclass 戦略を
|
||||
組み合わせる事も可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment" table="PAYMENT">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="PAYMENT_TYPE" type="string"/>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<subclass name="CreditCardPayment" discriminator-value="CREDIT">
|
||||
<join table="CREDIT_PAYMENT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</join>
|
||||
</subclass>
|
||||
<subclass name="CashPayment" discriminator-value="CASH">
|
||||
...
|
||||
</subclass>
|
||||
<subclass name="ChequePayment" discriminator-value="CHEQUE">
|
||||
...
|
||||
</subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
いずれのマッピング戦略であっても、ルートである <literal>Payment</literal> クラスへの
|
||||
ポリモーフィックな関連は <literal><many-to-one></literal> を使ってマッピングします。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcrete" revision="2">
|
||||
<title>具象クラスごとのテーブル(table-per-concrete-class)</title>
|
||||
|
||||
<para>
|
||||
table-per-concrete-class 戦略のマッピングに対するアプローチは、2つあります。
|
||||
1つ目は <literal><union-subclass></literal> を利用する方法です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Payment">
|
||||
<id name="id" type="long" column="PAYMENT_ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
<property name="amount" column="AMOUNT"/>
|
||||
...
|
||||
<union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<property name="creditCardType" column="CCTYPE"/>
|
||||
...
|
||||
</union-subclass>
|
||||
<union-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
...
|
||||
</union-subclass>
|
||||
<union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
...
|
||||
</union-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
サブクラスごとに3つのテーブルが必要です。それぞれのテーブルは、継承プロパティを含んだ、
|
||||
クラスの全てのプロパティに対するカラムを定義します。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
このアプローチには制限があります。
|
||||
それは、プロパティがスーパークラスにマッピングされていた場合、
|
||||
全てのサブクラスにおいてカラム名が同じでなければならないというものです。
|
||||
(Hibernateの今後のリリースで緩和されるかもしれません)。
|
||||
<union-subclass> を使った table-per-concrete-class 戦略では識別子生成戦略を使用できません。
|
||||
主キーを生成するためのシードは、全ての union subclass の階層内で共有する必要があるからです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
もしスーパークラスが抽象クラスなら、<literal>abstract="true"</literal>とマッピングします。
|
||||
もちろん、スーパークラスが抽象クラスでないなら、スーパークラスのインスタンスを
|
||||
保持するためのテーブルの追加が必要となります(上の例でのデフォルトは <literal>PAYMENT</literal> )。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritance-tableperconcreate-polymorphism">
|
||||
<title>暗黙的ポリモーフィズムを用いた table-per-concrete-class</title>
|
||||
|
||||
<para>
|
||||
もう一つのアプローチは暗黙的ポリモーフィズムの使用です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CREDIT_AMOUNT"/>
|
||||
...
|
||||
</class>
|
||||
|
||||
<class name="CashPayment" table="CASH_PAYMENT">
|
||||
<id name="id" type="long" column="CASH_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CASH_AMOUNT"/>
|
||||
...
|
||||
</class>
|
||||
|
||||
<class name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<id name="id" type="long" column="CHEQUE_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="amount" column="CHEQUE_AMOUNT"/>
|
||||
...
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>Payment</literal> インターフェイスがどこにも明示的に示されていないことに注意してください。
|
||||
そして、<literal>Payment</literal> プロパティがそれぞれのサブクラスにマッピングされていることにも注意してください。
|
||||
もし重複を避けたいのであれば、XMLエンティティの利用を考えてください。
|
||||
(例: <literal>DOCTYPE</literal> 宣言における <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
|
||||
と、マッピングにおける <literal>&allproperties;</literal>)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
このアプローチの欠点は、Hibernateがポリモーフィックなクエリの実行時にSQL <literal>UNION</literal>
|
||||
を生成しない点です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
このマッピング戦略に対しては、<literal>Payment</literal> へのポリモーフィックな関連は
|
||||
通常、<literal><any></literal> を使ってマッピングされます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
|
||||
<meta-value value="CREDIT" class="CreditCardPayment"/>
|
||||
<meta-value value="CASH" class="CashPayment"/>
|
||||
<meta-value value="CHEQUE" class="ChequePayment"/>
|
||||
<column name="PAYMENT_CLASS"/>
|
||||
<column name="PAYMENT_ID"/>
|
||||
</any>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="inheritace-mixingpolymorphism">
|
||||
<title>他の継承マッピングと暗黙的ポリモーフィズムの組み合わせ</title>
|
||||
|
||||
<para>
|
||||
このマッピングについての更なる注意点があります。
|
||||
サブクラスが自身を <literal><class></literal> 要素としてマッピングしているので、
|
||||
(かつ <literal>Payment</literal> は単なるインターフェイスなので)、
|
||||
それぞれのサブクラスは簡単にその他の継承階層の一部となります。
|
||||
(しかも、今までどおり <literal>Payment</literal> インターフェイスに対するポリモーフィックなクエリ
|
||||
を使用することができます)
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
|
||||
<id name="id" type="long" column="CREDIT_PAYMENT_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<discriminator column="CREDIT_CARD" type="string"/>
|
||||
<property name="amount" column="CREDIT_AMOUNT"/>
|
||||
...
|
||||
<subclass name="MasterCardPayment" discriminator-value="MDC"/>
|
||||
<subclass name="VisaPayment" discriminator-value="VISA"/>
|
||||
</class>
|
||||
|
||||
<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
|
||||
<id name="id" type="long" column="TXN_ID">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
...
|
||||
<joined-subclass name="CashPayment" table="CASH_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="amount" column="CASH_AMOUNT"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
<joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
|
||||
<key column="PAYMENT_ID"/>
|
||||
<property name="amount" column="CHEQUE_AMOUNT"/>
|
||||
...
|
||||
</joined-subclass>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
もう一度述べますが、<literal>Payment</literal> は明示的に定義されません。
|
||||
もし、<literal>Payment</literal> インターフェイスに対してクエリを実行するなら
|
||||
(例えば <literal>from Payment</literal> 節を使って)、
|
||||
Hibernateは自動的に <literal>CreditCardPayment</literal>
|
||||
(とCreditCardPaymentのサブクラス、<literal>Payment</literal> の実装であるため)、
|
||||
および、<literal>CashPayment</literal> 、<literal>ChequePayment</literal>
|
||||
のインスタンスを返します。
|
||||
<literal>NonelectronicTransaction</literal> インスタンスは返しません。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="inheritance-limitations">
|
||||
<title>制限</title>
|
||||
|
||||
<para>
|
||||
table-per-concrete-class マッピング戦略への「暗黙的ポリモーフィズム」アプローチには
|
||||
いくつかの制限があります。<literal><union-subclass></literal> マッピングに対しても
|
||||
少し弱めの制限があります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
次のテーブルに、Hibernateにおけるtable-per-concrete-classマッピングの
|
||||
制限や暗黙的ポリモーフィズムの制限を示します。
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title>継承マッピングの機能</title>
|
||||
<tgroup cols='8' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname='c1' colwidth="1*"/>
|
||||
<colspec colname='c2' colwidth="1*"/>
|
||||
<colspec colname='c3' colwidth="1*"/>
|
||||
<colspec colname='c4' colwidth="1*"/>
|
||||
<colspec colname='c5' colwidth="1*"/>
|
||||
<colspec colname='c6' colwidth="1*"/>
|
||||
<colspec colname='c7' colwidth="1*"/>
|
||||
<colspec colname='c8' colwidth="1*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>継承戦略</entry>
|
||||
<entry>多対一のポリモーフィズム</entry>
|
||||
<entry>一対一のポリモーフィズム</entry>
|
||||
<entry>一対多のポリモーフィズム</entry>
|
||||
<entry>多対多のポリモーフィズム</entry>
|
||||
<entry>ポリモーフィズムを使った<literal>load()/get()</literal></entry>
|
||||
<entry>ポリモーフィズムを使ったクエリ</entry>
|
||||
<entry>ポリモーフィズムを使った結合</entry>
|
||||
<entry>外部結合によるフェッチ</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>table per class-hierarchy</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal></entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>サポート</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per subclass</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal></entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>サポート</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per concrete-class (union-subclass)</entry>
|
||||
<entry><literal><many-to-one></literal></entry>
|
||||
<entry><literal><one-to-one></literal></entry>
|
||||
<entry><literal><one-to-many></literal> (for <literal>inverse="true"</literal> only)</entry>
|
||||
<entry><literal><many-to-many></literal></entry>
|
||||
<entry><literal>s.get(Payment.class, id)</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><literal>from Order o join o.payment p</literal></entry>
|
||||
<entry><emphasis>サポート</emphasis></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>table per concrete class (implicit polymorphism)</entry>
|
||||
<entry><literal><any></literal></entry>
|
||||
<entry><emphasis>サポートしていません</emphasis></entry>
|
||||
<entry><emphasis>サポートしていません</emphasis></entry>
|
||||
<entry><literal><many-to-any></literal></entry>
|
||||
<entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
|
||||
<entry><literal>from Payment p</literal></entry>
|
||||
<entry><emphasis>サポートしていません</emphasis></entry>
|
||||
<entry><emphasis>サポートしていません</emphasis></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,539 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="persistent-classes" revision="2">
|
||||
<title>永続クラス</title>
|
||||
|
||||
<para>
|
||||
永続クラスはビジネス上の問題のエンティティ(例えば、Eコマースアプリケーションの顧客や注文)
|
||||
を実装するアプリケーションのクラスです。
|
||||
永続クラスのすべてのインスタンスが永続状態であると見なされるわけではありません。
|
||||
インスタンスは逆に一時的(transient)であったり、分離状態(detached)であったりするかもしれません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Plain Old Java Object (POJO)プログラミングモデルとしても知られる
|
||||
いくつかの単純なルールに従うなら、Hibernateは最もよく働きます。
|
||||
しかしこれらのルールは難しいものではありません。
|
||||
実際Hibernate3は永続オブジェクトの性質にほとんど何の前提も置いていません。
|
||||
ドメインモデルは他の方法で表現することもできます。
|
||||
例えば <literal>Map</literal> インスタンスのツリーを使う方法があります。
|
||||
</para>
|
||||
|
||||
<sect1 id="persistent-classes-pojo">
|
||||
<title>単純なPOJOの例</title>
|
||||
|
||||
<para>
|
||||
ほとんどのJavaアプリケーションにはネコ科の動物を表現する永続クラスが必要です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
|
||||
public class Cat {
|
||||
private Long id; // identifier
|
||||
|
||||
private Date birthdate;
|
||||
private Color color;
|
||||
private char sex;
|
||||
private float weight;
|
||||
private int litterId;
|
||||
|
||||
private Cat mother;
|
||||
private Set kittens = new HashSet();
|
||||
|
||||
private void setId(Long id) {
|
||||
this.id=id;
|
||||
}
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setBirthdate(Date date) {
|
||||
birthdate = date;
|
||||
}
|
||||
public Date getBirthdate() {
|
||||
return birthdate;
|
||||
}
|
||||
|
||||
void setWeight(float weight) {
|
||||
this.weight = weight;
|
||||
}
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
void setSex(char sex) {
|
||||
this.sex=sex;
|
||||
}
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
void setLitterId(int id) {
|
||||
this.litterId = id;
|
||||
}
|
||||
public int getLitterId() {
|
||||
return litterId;
|
||||
}
|
||||
|
||||
void setMother(Cat mother) {
|
||||
this.mother = mother;
|
||||
}
|
||||
public Cat getMother() {
|
||||
return mother;
|
||||
}
|
||||
void setKittens(Set kittens) {
|
||||
this.kittens = kittens;
|
||||
}
|
||||
public Set getKittens() {
|
||||
return kittens;
|
||||
}
|
||||
|
||||
// addKitten not needed by Hibernate
|
||||
public void addKitten(Cat kitten) {
|
||||
kitten.setMother(this);
|
||||
kitten.setLitterId( kittens.size() );
|
||||
kittens.add(kitten);
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
従うべき4つのルールがあります:
|
||||
</para>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-constructor" revision="1">
|
||||
<title>引数のないコンストラクタを実装する</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> には引数のないコンストラクタがあります。
|
||||
Hibernateが <literal>Constructor.newInstance()</literal> を使って永続クラスの
|
||||
インスタンス化を行えるように、すべての永続クラスにはデフォルトコンストラクタ
|
||||
(publicでなくても構いません)がなければなりません。
|
||||
Hibernateの実行時プロキシ生成のために、少なくとも <emphasis>package</emphasis>
|
||||
の可視性を持つデフォルトコンストラクタを強くお勧めします。
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-identifier" revision="2">
|
||||
<title>識別子プロパティを用意する(オプション)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> には <literal>id</literal> というプロパティがあります。
|
||||
このプロパティはデータベーステーブルの主キーカラムへマッピングされます。
|
||||
このプロパティの名前は何でも構いませんし、型はどのようなプリミティブ型でも、
|
||||
プリミティブの「ラッパー」型でも、<literal>java.lang.String</literal> や
|
||||
<literal>java.util.Date</literal> でも構いません。
|
||||
(もしレガシーデータベーステーブルが複合キーを持つならば、
|
||||
今述べたような型のプロパティを持つユーザ定義のクラスを使うことさえ可能です。
|
||||
後で複合識別子の節を見てください。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
識別子プロパティは厳密にはオプションです。
|
||||
これを省略して、Hibernateに内部的にオブジェクトの識別子を追跡させることは可能です。
|
||||
しかしおすすめはしません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
実際に、識別子プロパティを宣言するクラスだけが利用可能な機能がいくつかあります:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
分離オブジェクトの連鎖的な再追加(カスケード更新やカスケードマージ)。
|
||||
<xref linkend="objectstate-transitive"/> を参照してください。
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session.saveOrUpdate()</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>Session.merge()</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
永続クラスには、一貫した名前の識別子プロパティを定義することをお勧めします。
|
||||
さらにnull値を取れる(つまりプリミティブではない)型を使った方がよいでしょう。
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-final">
|
||||
<title>finalクラスにしない(オプション)</title>
|
||||
<para>
|
||||
Hibernateの中心的な特徴である <emphasis>プロキシ</emphasis> は、
|
||||
永続クラスがfinalでないこと、またはメソッドを全部publicで宣言している
|
||||
インターフェイスが実装されているかに依存しています。
|
||||
</para>
|
||||
<para>
|
||||
Hibernateでインターフェイスを実装していない <literal>final</literal> クラスを永続化することはできますが、
|
||||
遅延関連フェッチに対してプロキシを使うことはできなくなります。
|
||||
これはパフォーマンスチューニングへの選択肢を狭めることになります。
|
||||
</para>
|
||||
<para>
|
||||
finalではないクラスで <literal>public final</literal> メソッドを定義することも避けるべきです。
|
||||
<literal>public final</literal> メソッドを持つクラスを使いたければ、
|
||||
<literal>lazy="false"</literal> と設定して明示的にプロキシを無効にしなければなりません。
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="persistent-classes-pojo-accessors" revision="2">
|
||||
<title>永続フィールドに対するアクセサとミューテータを定義する(オプション)</title>
|
||||
|
||||
<para>
|
||||
<literal>Cat</literal> ではすべての永続フィールドに対してアクセサメソッドを定義しています。
|
||||
他の多くのORMツールは、永続インスタンス変数を直接永続化します。
|
||||
私たちはリレーショナルスキーマとクラスの内部構造を分離する方が良いと信じています。
|
||||
デフォルトでは、HibernateはJavaBeanスタイルのプロパティを永続化し、
|
||||
<literal>getFoo</literal>, <literal>isFoo</literal>, <literal>setFoo</literal>
|
||||
形式のメソッド名を認識します。
|
||||
しかし必要なら、特定のプロパティに対して、直接のフィールドアクセスに切り替えることは可能です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
プロパティはpublicで宣言する必要は <emphasis>ありません</emphasis> 。
|
||||
Hibernateはデフォルト、<literal>protected</literal> もしくは <literal>private</literal>
|
||||
のget / setのペアを持つプロパティを永続化することができます。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-inheritance">
|
||||
<title>継承の実装</title>
|
||||
|
||||
<para>
|
||||
サブクラスも1番目と2番目のルールを守らなければなりません。
|
||||
サブクラスはスーパークラス <literal>Cat</literal> から識別子プロパティを継承します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[package eg;
|
||||
|
||||
public class DomesticCat extends Cat {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
protected void setName(String name) {
|
||||
this.name=name;
|
||||
}
|
||||
}]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-equalshashcode" revision="1">
|
||||
<title><literal>equals()</literal> と <literal>hashCode()</literal> の実装</title>
|
||||
|
||||
<para>
|
||||
以下の条件の場合、
|
||||
<literal>equals()</literal> と <literal>hashCode()</literal> メソッドをオーバーライドしなければなりません、
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
永続クラスのインスタンスを <literal>Set</literal> に置く場合。
|
||||
(これは多値の関連を表現するおすすめの方法です)
|
||||
<emphasis>そして同時に</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
分離インスタンスをセッションへ再追加する場合。
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Hibernateは、永続ID(データベースの行)と、特定のセッションスコープ内に
|
||||
限定ですがJavaIDとが等価であることを保証します。
|
||||
ですから異なるセッションで検索したインスタンスを組み合わせる場合、
|
||||
<literal>Set</literal> に意味のあるセマンティクスを持たせようと思っているなら
|
||||
すぐに<literal>equals()</literal> と <literal>hashCode()</literal>
|
||||
を実装しなければなりません。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
最も明白な方法は、両方のオブジェクトの識別子の値の比較によって <literal>equals()</literal>と
|
||||
<literal>hashCode()</literal> を実装する方法です。
|
||||
値が同じなら、両者はデータベースの同じ行でなければならないため等しくなります。
|
||||
(両者が <literal>Set</literal> に追加されても、
|
||||
<literal>Set</literal> には1個の要素しかないことになります)
|
||||
残念なことに、生成された識別子にはこのアプローチを使うことができません。
|
||||
Hibernateは永続化されたオブジェクトへ識別子の値を代入するだけであり、
|
||||
新しく作成されたインスタンスはどのような識別子の値も持っていません。
|
||||
さらに、インスタンスがセーブされておらず、現在 <literal>Set</literal> の中にあれば、
|
||||
セーブするとオブジェクトへ識別子の値を代入することになります。
|
||||
もし <literal>equals()</literal> と <literal>hashCode()</literal> が識別子の値に基づいているなら、
|
||||
ハッシュコードが変更されると <literal>Set</literal> の規約が破られます。
|
||||
この問題についての完全な議論は、Hibernateのウェブサイトを見てください。
|
||||
これはHibernateの問題ではなく、オブジェクトの同一性と等価性についての、
|
||||
通常のJavaのセマンティクスであることに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>ビジネスキーの等価性</emphasis> を使って、
|
||||
<literal>equals()</literal> と <literal>hashCode()</literal> を実装することをお勧めします。
|
||||
ビジネスキーの等価性とは、<literal>equals()</literal> メソッドが、ビジネスキー、
|
||||
つまり現実の世界においてインスタンスを特定するキー(<emphasis>自然</emphasis> 候補キー)
|
||||
を形成するプロパティだけを比較することを意味します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[public class Cat {
|
||||
|
||||
...
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) return true;
|
||||
if ( !(other instanceof Cat) ) return false;
|
||||
|
||||
final Cat cat = (Cat) other;
|
||||
|
||||
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
|
||||
if ( !cat.getMother().equals( getMother() ) ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = getMother().hashCode();
|
||||
result = 29 * result + getLitterId();
|
||||
return result;
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
ビジネスキーはデータベースの主キー候補ほど安定である必要はないことに注意してください
|
||||
(<xref linkend="transactions-basics-identity"/> を見てください)。
|
||||
更新不可なプロパティやユニークなプロパティは、通常ビジネスキーのよい候補です。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-dynamicmodels">
|
||||
<title>動的モデル</title>
|
||||
|
||||
<para>
|
||||
<emphasis>以下の機能は現在実験段階にあると見なされており、
|
||||
近い将来変更される可能性があることに注意してください。</emphasis>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
永続エンティティは、必ずしも実行時にPOJOクラスやJavaBeanオブジェクトで表現する必要はありません。
|
||||
Hibernateは(実行時に <literal>Map</literal> の <literal>Map</literal> を使う)動的モデルと、
|
||||
DOM4Jツリーとしてのエンティティの表現もサポートします。
|
||||
このアプローチを使うと永続クラスを書かず、マッピングファイルだけを書くことになります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
デフォルトでは、Hibernateは通常のPOJOモードで動作します。
|
||||
<literal>default_entity_mode</literal> 設定オプションを使って、
|
||||
特定の <literal>SessionFactory</literal> に対するデフォルトのエンティティ表現モードを設定することができます
|
||||
(<xref linkend="configuration-optional-properties"/> を見てください)。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
以下の例では <literal>Map</literal> を使った表現を紹介します。
|
||||
まずマッピングファイルで、クラス名の代わりに(またはそれに加えて)
|
||||
<literal>entity-name</literal> を定義しなければなりません:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
|
||||
<class entity-name="Customer">
|
||||
|
||||
<id name="id"
|
||||
type="long"
|
||||
column="ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
|
||||
<property name="name"
|
||||
column="NAME"
|
||||
type="string"/>
|
||||
|
||||
<property name="address"
|
||||
column="ADDRESS"
|
||||
type="string"/>
|
||||
|
||||
<many-to-one name="organization"
|
||||
column="ORGANIZATION_ID"
|
||||
class="Organization"/>
|
||||
|
||||
<bag name="orders"
|
||||
inverse="true"
|
||||
lazy="false"
|
||||
cascade="all">
|
||||
<key column="CUSTOMER_ID"/>
|
||||
<one-to-many class="Order"/>
|
||||
</bag>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>]]></programlisting>
|
||||
|
||||
<para>
|
||||
関連がターゲットのクラス名を使って定義していたとしても、
|
||||
関連のターゲット型もPOJOではなく動的なエンティティでも構わないことに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>SessionFactory</literal> に対してデフォルトのエンティティモードを
|
||||
<literal>dynamic-map</literal> に設定した後、
|
||||
実行時に <literal>Map</literal> の <literal>Map</literal> を使うことができます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session s = openSession();
|
||||
Transaction tx = s.beginTransaction();
|
||||
Session s = openSession();
|
||||
|
||||
// Create a customer
|
||||
Map david = new HashMap();
|
||||
david.put("name", "David");
|
||||
|
||||
// Create an organization
|
||||
Map foobar = new HashMap();
|
||||
foobar.put("name", "Foobar Inc.");
|
||||
|
||||
// Link both
|
||||
david.put("organization", foobar);
|
||||
|
||||
// Save both
|
||||
s.save("Customer", david);
|
||||
s.save("Organization", foobar);
|
||||
|
||||
tx.commit();
|
||||
s.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
動的なマッピングの利点は、エンティティクラスの実装を必要としないため、
|
||||
プロトタイピングに要するターンアラウンドタイムが早いということです。
|
||||
しかしコンパイル時の型チェックがないので、実行時に非常に多くの例外処理を扱わなければならないでしょう。
|
||||
Hibernateマッピングのおかげで、データベーススキーマは容易に正規化でき、健全になり、
|
||||
後で適切なドメインモデルの実装を追加することが可能になります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
エンティティ表現モードは <literal>Session</literal> ごとに設定することも可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
|
||||
|
||||
// Create a customer
|
||||
Map david = new HashMap();
|
||||
david.put("name", "David");
|
||||
dynamicSession.save("Customer", david);
|
||||
...
|
||||
dynamicSession.flush();
|
||||
dynamicSession.close()
|
||||
...
|
||||
// Continue on pojoSession
|
||||
]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
<literal>EntityMode</literal> を使った <literal>getSession()</literal>
|
||||
の呼び出しは <literal>SessionFactory</literal> ではなく <literal>Session</literal>
|
||||
APIにあることに注意してください。
|
||||
その方法では、新しい <literal>Session</literal> は、ベースとなるJDBCコネクション、
|
||||
トランザクション、その他のコンテキスト情報を共有します。
|
||||
これは2番目の <literal>Session</literal> では <literal>flush()</literal> と <literal>close()</literal>
|
||||
を呼ぶ必要がないということ、そのためトランザクションとコネクションの管理を
|
||||
1番目の作業単位(Unit of Work)に任せることができるということです。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
XML表現の能力についてのさらなる情報は <xref linkend="xml"/> で見つかります。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="persistent-classes-tuplizers" revision="0">
|
||||
<title>Tuplizer</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.tuple.Tuplizer</literal> とそのサブインターフェイスは、
|
||||
表現の <literal>org.hibernate.EntityMode</literal> を利用して、
|
||||
データ断片のある表現の管理に責任を持ちます。
|
||||
与えられたデータ断片をデータ構造として考えるなら、Tuplizerはそのようなデータ構造を
|
||||
どのように作成するかを知り、そのようなデータ構造からどのように値を抽出し、
|
||||
注入するかを知っています。
|
||||
例えばPOJOエンティティモードでは、対応するTuplizerはコンストラクタを通して、
|
||||
POJOをどのように作成するか、定義されたプロパティアクセサを使い、
|
||||
POJOプロパティにどのようにアクセスするかを知ります。
|
||||
Tuplizerには二つのハイレベルの型があります。
|
||||
それらは、<literal>org.hibernate.tuple.EntityTuplizer</literal> と
|
||||
<literal>org.hibernate.tuple.ComponentTuplizer</literal> インターフェイスで表現されます。
|
||||
<literal>EntityTuplizer</literal> は上で述べたようなエンティティに関する契約の管理に責任を持ちます。
|
||||
一方、<literal>ComponentTuplizer</literal> はコンポーネントに関する契約の管理に責任を持ちます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
ユーザは独自のTuplizerに差し替えることも可能です。
|
||||
おそらくdynamic-map entity-modeの際に <literal>java.util.HashMap</literal> を使うのではなく、
|
||||
<literal>java.util.Map</literal> の実装が必要でしょう。
|
||||
もしくは、おそらくデフォルトのものではなく、別のプロキシ生成戦略の定義が必要でしょう。
|
||||
両者とも、カスタムのTuplizer実装を定義することで達成されます。
|
||||
Tuplizerの定義は、管理しようとするエンティティやコンポーネントのマッピングに結び付けられます。
|
||||
顧客エンティティの例に戻ると:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<hibernate-mapping>
|
||||
<class entity-name="Customer">
|
||||
<!--
|
||||
Override the dynamic-map entity-mode
|
||||
tuplizer for the customer entity
|
||||
-->
|
||||
<tuplizer entity-mode="dynamic-map"
|
||||
class="CustomMapTuplizerImpl"/>
|
||||
|
||||
<id name="id" type="long" column="ID">
|
||||
<generator class="sequence"/>
|
||||
</id>
|
||||
|
||||
<!-- other properties -->
|
||||
...
|
||||
</class>
|
||||
</hibernate-mapping>
|
||||
|
||||
|
||||
public class CustomMapTuplizerImpl
|
||||
extends org.hibernate.tuple.DynamicMapEntityTuplizer {
|
||||
// override the buildInstantiator() method to plug in our custom map...
|
||||
protected final Instantiator buildInstantiator(
|
||||
org.hibernate.mapping.PersistentClass mappingInfo) {
|
||||
return new CustomMapInstantiator( mappingInfo );
|
||||
}
|
||||
|
||||
private static final class CustomMapInstantiator
|
||||
extends org.hibernate.tuple.DynamicMapInstantitor {
|
||||
// override the generateMap() method to return our custom map...
|
||||
protected final Map generateMap() {
|
||||
return new CustomMap();
|
||||
}
|
||||
}
|
||||
}]]></programlisting>
|
||||
|
||||
|
||||
</sect1>
|
||||
|
||||
<para>
|
||||
<!-- TODO: プロパティとプロキシパッケージのユーザ拡張フレームワークを文書化すること -->
|
||||
</para>
|
||||
|
||||
</chapter>
|
||||
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="querycriteria">
|
||||
<title>Criteriaクエリ</title>
|
||||
|
||||
<para>
|
||||
Hibernateには、直感的で拡張可能なcriteriaクエリAPIが用意されています。
|
||||
</para>
|
||||
|
||||
<sect1 id="querycriteria-creating">
|
||||
<title> <literal>Criteria</literal> インスタンスの作成</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.Criteria</literal>
|
||||
インターフェイスは特定の永続性クラスに対するクエリを表現します。
|
||||
<literal>Session</literal> は <literal>Criteria</literal> インスタンスのファクトリです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
|
||||
crit.setMaxResults(50);
|
||||
List cats = crit.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-narrowing">
|
||||
<title>リザルトセットの絞込み</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Criterion</literal> インターフェイスのインスタンスは、
|
||||
個別のクエリクライテリオン(問い合わせの判定基準)を表します。
|
||||
<literal>org.hibernate.criterion.Restrictions</literal>
|
||||
クラスは、ある組み込みの <literal>Criterion</literal>
|
||||
型を取得するためのファクトリメソッドを持っています。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.add( Restrictions.between("weight", minWeight, maxWeight) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
Restriction(限定)は、論理的にグループ化できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.add( Restrictions.or(
|
||||
Restrictions.eq( "age", new Integer(0) ),
|
||||
Restrictions.isNull("age")
|
||||
) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
|
||||
.add( Restrictions.disjunction()
|
||||
.add( Restrictions.isNull("age") )
|
||||
.add( Restrictions.eq("age", new Integer(0) ) )
|
||||
.add( Restrictions.eq("age", new Integer(1) ) )
|
||||
.add( Restrictions.eq("age", new Integer(2) ) )
|
||||
) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
元々あるCriterion型(<literal>Restrictions</literal> のサブクラス)
|
||||
はかなりの範囲に及びますが、特に有用なのはSQLを直接指定できるものです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>{alias}</literal> というプレースホルダは、
|
||||
問い合わせを受けたエンティティの行の別名によって置き換えられます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
criterionを得る別の手段は、
|
||||
<literal>Property</literal> インスタンスから取得することです。
|
||||
<literal>Property.forName()</literal> を呼び出して、
|
||||
<literal>Property</literal> インスタンスを作成できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
Property age = Property.forName("age");
|
||||
List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.disjunction()
|
||||
.add( age.isNull() )
|
||||
.add( age.eq( new Integer(0) ) )
|
||||
.add( age.eq( new Integer(1) ) )
|
||||
.add( age.eq( new Integer(2) ) )
|
||||
) )
|
||||
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-ordering">
|
||||
<title>結果の整列</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Order</literal>
|
||||
を使って結果を並び替えることができます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "F%")
|
||||
.addOrder( Order.asc("name") )
|
||||
.addOrder( Order.desc("age") )
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Property.forName("name").like("F%") )
|
||||
.addOrder( Property.forName("name").asc() )
|
||||
.addOrder( Property.forName("age").desc() )
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-associations" revision="2">
|
||||
<title>関連</title>
|
||||
|
||||
<para>
|
||||
<literal>createCriteria()</literal> を使い、関連をナビゲートすることで、
|
||||
容易に関係するエンティティに制約を指定できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "F%") )
|
||||
.createCriteria("kittens")
|
||||
.add( Restrictions.like("name", "F%") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
2番目の <literal>createCriteria()</literal> は、<literal>kittens</literal>
|
||||
コレクションの要素を参照する新しい <literal>Criteria</literal>
|
||||
インスタンスを返すことに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
以下のような方法も、状況により有用です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.createAlias("kittens", "kt")
|
||||
.createAlias("mate", "mt")
|
||||
.add( Restrictions.eqProperty("kt.name", "mt.name") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
(<literal>createAlias()</literal> は新しい
|
||||
<literal>Criteria</literal> インスタンスを作成しません。)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
前の2つのクエリによって返される <literal>Cat</literal>
|
||||
インスタンスによって保持されるkittensコレクションは、
|
||||
criteriaによって事前にフィルタリング <emphasis>されない</emphasis>
|
||||
ことに注意してください。
|
||||
もしcriteriaに適合するkittenを取得したいなら、
|
||||
<literal>ResultTransformer</literal> を使わなければなりません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.createCriteria("kittens", "kt")
|
||||
.add( Restrictions.eq("name", "F%") )
|
||||
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
|
||||
.list();
|
||||
Iterator iter = cats.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map map = (Map) iter.next();
|
||||
Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
|
||||
Cat kitten = (Cat) map.get("kt");
|
||||
}]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-dynamicfetching" revision="1">
|
||||
<title>関連の動的フェッチ</title>
|
||||
|
||||
<para>
|
||||
<literal>setFetchMode()</literal> を使い、
|
||||
実行時に関連の復元方法を指定してもよいです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
|
||||
.add( Restrictions.like("name", "Fritz%") )
|
||||
.setFetchMode("mate", FetchMode.EAGER)
|
||||
.setFetchMode("kittens", FetchMode.EAGER)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
このクエリは外部結合により <literal>mate</literal> と
|
||||
<literal>kittens</literal> の両方をフェッチします。
|
||||
より多くの情報は <xref linkend="performance-fetching"/> を参照してください。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-examples">
|
||||
<title>クエリの例</title>
|
||||
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Example</literal> クラスは、
|
||||
与えられたインスタンスからクエリクライテリオンを構築できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Cat cat = new Cat();
|
||||
cat.setSex('F');
|
||||
cat.setColor(Color.BLACK);
|
||||
List results = session.createCriteria(Cat.class)
|
||||
.add( Example.create(cat) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
バージョンプロパティ、識別子、関連は無視されます。
|
||||
デフォルトではnull値のプロパティは除外されます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
どのように <literal>Example</literal> を適用するか
|
||||
調整することができます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Example example = Example.create(cat)
|
||||
.excludeZeroes() //exclude zero valued properties
|
||||
.excludeProperty("color") //exclude the property named "color"
|
||||
.ignoreCase() //perform case insensitive string comparisons
|
||||
.enableLike(); //use like for string comparisons
|
||||
List results = session.createCriteria(Cat.class)
|
||||
.add(example)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
関連オブジェクトにcriteriaを指定するために、Exampleを使うことも可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.add( Example.create(cat) )
|
||||
.createCriteria("mate")
|
||||
.add( Example.create( cat.getMate() ) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-projection">
|
||||
<title>射影、集約、グループ化</title>
|
||||
<para>
|
||||
<literal>org.hibernate.criterion.Projections</literal> クラスは
|
||||
<literal>Projection</literal> インスタンスのファクトリです。
|
||||
<literal>setProjection()</literal> を呼び出すことで、
|
||||
クエリに射影を適用します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.rowCount() )
|
||||
.add( Restrictions.eq("color", Color.BLACK) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount() )
|
||||
.add( Projections.avg("weight") )
|
||||
.add( Projections.max("weight") )
|
||||
.add( Projections.groupProperty("color") )
|
||||
)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
必要であっても、criteriaクエリに「group by」を明示する必要はありません。
|
||||
ある種のProjection型は <emphasis>グループ化射影</emphasis> として定義され、
|
||||
SQLの <literal>group by</literal> 節にも現れます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
任意で射影に別名を付けられるため、射影される値はrestrictionやordering内から参照できます。
|
||||
別名をつける2つの異なる方法を示します。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
|
||||
.addOrder( Order.asc("colr") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.groupProperty("color").as("colr") )
|
||||
.addOrder( Order.asc("colr") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>alias()</literal> と <literal>as()</literal> メソッドは、
|
||||
Projectionインスタンスを別の名前の <literal>Projection</literal> インスタンスで
|
||||
ラップするだけです。
|
||||
ショートカットとして、射影を射影リストに追加する際に、別名をつけられます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount(), "catCountByColor" )
|
||||
.add( Projections.avg("weight"), "avgWeight" )
|
||||
.add( Projections.max("weight"), "maxWeight" )
|
||||
.add( Projections.groupProperty("color"), "color" )
|
||||
)
|
||||
.addOrder( Order.desc("catCountByColor") )
|
||||
.addOrder( Order.desc("avgWeight") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
|
||||
.createAlias("kittens", "kit")
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.property("cat.name"), "catName" )
|
||||
.add( Projections.property("kit.name"), "kitName" )
|
||||
)
|
||||
.addOrder( Order.asc("catName") )
|
||||
.addOrder( Order.asc("kitName") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
射影の式に <literal>Property.forName()</literal> も使用できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Property.forName("name") )
|
||||
.add( Property.forName("color").eq(Color.BLACK) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List results = session.createCriteria(Cat.class)
|
||||
.setProjection( Projections.projectionList()
|
||||
.add( Projections.rowCount().as("catCountByColor") )
|
||||
.add( Property.forName("weight").avg().as("avgWeight") )
|
||||
.add( Property.forName("weight").max().as("maxWeight") )
|
||||
.add( Property.forName("color").group().as("color" )
|
||||
)
|
||||
.addOrder( Order.desc("catCountByColor") )
|
||||
.addOrder( Order.desc("avgWeight") )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-detachedqueries">
|
||||
<title>クエリおよびサブクエリの分離</title>
|
||||
<para>
|
||||
<literal>DetachedCriteria</literal> クラスにより、
|
||||
セッションスコープ外にクエリを作成できます。
|
||||
後で、任意の <literal>Session</literal> を使って、実行できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
|
||||
.add( Property.forName("sex").eq('F') );
|
||||
|
||||
Session session = ....;
|
||||
Transaction txn = session.beginTransaction();
|
||||
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
|
||||
txn.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>DetachedCriteria</literal> は、サブクエリを表現するためにも使えます。
|
||||
サブクエリを伴うCriterionインスタンスは、
|
||||
<literal>Subqueries</literal> もしくは <literal>Property</literal> から得られます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
|
||||
.setProjection( Property.forName("weight").avg() );
|
||||
session.createCriteria(Cat.class)
|
||||
.add( Property.forName("weight).gt(avgWeight) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
|
||||
.setProjection( Property.forName("weight") );
|
||||
session.createCriteria(Cat.class)
|
||||
.add( Subqueries.geAll("weight", weights) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>
|
||||
相互関係があるサブクエリでさえも可能です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
|
||||
.setProjection( Property.forName("weight").avg() )
|
||||
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
|
||||
session.createCriteria(Cat.class, "cat")
|
||||
.add( Property.forName("weight).gt(avgWeightForSex) )
|
||||
.list();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
|
||||
user objects - similar to setResultClass in JDO2. General use of ResultTransformer
|
||||
could also be explained. -->
|
||||
|
||||
<sect1 id="query-criteria-naturalid">
|
||||
<title>自然識別子によるクエリ</title>
|
||||
|
||||
<para>
|
||||
criteriaクエリを含むたいていのクエリにとって、
|
||||
クエリキャッシュはあまり効率がよくないです。
|
||||
なぜなら、クエリキャッシュが頻繁に無効になるためです。
|
||||
しかしながら、キャッシュを無効にするアルゴリズムを最適化できる
|
||||
特別なクエリの種類が1つあります。
|
||||
更新されない自然キーによる検索です。
|
||||
いくつかのアプリケーションでは、この種類のクエリが頻繁に現れます。
|
||||
このような使われ方のために、criteria APIは特別な対策を提供します。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
最初に、<literal><natural-id></literal> を使って、
|
||||
エンティティの自然キーをマップしてください。
|
||||
そして、二次キャッシュを有効にします。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="User">
|
||||
<cache usage="read-write"/>
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<natural-id>
|
||||
<property name="name"/>
|
||||
<property name="org"/>
|
||||
</natural-id>
|
||||
<property name="password"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
注意: <emphasis>変更される</emphasis> 自然キーを持つエンティティに
|
||||
この機能を使うのは、意図されていない使い方です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
次に、Hibernateクエリキャッシュを有効にします。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
これで、<literal>Restrictions.naturalId()</literal> により、
|
||||
より効率的なキャッシュアルゴリズムを使用できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[session.createCriteria(User.class)
|
||||
.add( Restrictions.naturalId()
|
||||
.set("name", "gavin")
|
||||
.set("org", "hb")
|
||||
).setCacheable(true)
|
||||
.uniqueResult();]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,548 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="querysql" revision="2">
|
||||
<title>ネイティブSQL</title>
|
||||
|
||||
<para>データベースのネイティブSQL方言を使ってクエリを表現することもできます。
|
||||
クエリヒントやOracleの <literal>CONNECT</literal> キーワードのように、
|
||||
データベース独自の機能を利用したいときに使えます。
|
||||
SQL/JDBCを直接使用しているアプリケーションからHibernateへの移行も容易にしています。</para>
|
||||
|
||||
<para>Hibernate3では、生成、更新、削除、読み込み処理のようなすべての
|
||||
SQL(ストアドプロシージャを含む)を手書きできます。</para>
|
||||
|
||||
<sect1 id="querysql-creating" revision="3">
|
||||
<title> <literal>SQLQuery</literal> の使用</title>
|
||||
|
||||
<para>ネイティブなSQLクエリの実行は <literal>SQLQuery</literal>
|
||||
インターフェイスを通して制御します。
|
||||
<literal>SQLQuery</literal> インターフェイスは
|
||||
<literal>Session.createSQLQuery()</literal> を呼び出して取得します。
|
||||
非常に簡単な場合、次のような形を使えます。</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery("select * from cats")
|
||||
.addEntity(Cat.class)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>このクエリで指定されているものを下記に示します。</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>SQLクエリ文字列</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>クエリが返すエンティティ</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>ここでは、
|
||||
リザルトセットの列名は、マッピングファイルで指定された列名と同じだと仮定されます。
|
||||
これは同じ列名を持つ複数のテーブルを結合するSQLクエリでは問題となります。
|
||||
次の形は、列名が重複しても弱みになりません。</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
|
||||
.addEntity("cat", Cat.class)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>このクエリで指定されているものを下記に示します。</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>SQLクエリ文字列
|
||||
(Hibernateが列の別名を挿入するためのプレースホルダを含む)</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>クエリが返すエンティティとSQLテーブルの別名</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para><literal>addEntity()</literal> メソッドにより、
|
||||
SQLのテーブル別名と返されるエンティティクラスを関連付け、
|
||||
クエリのリザルトセットの構造を決定します。</para>
|
||||
|
||||
<para><literal>addJoin()</literal> メソッドを使い、
|
||||
他のエンティティとの関連とコレクションをロードします。</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
||||
)
|
||||
.addEntity("cat", Cat.class)
|
||||
.addJoin("kitten", "cat.kittens")
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>ネイティブSQLクエリは、単純なスカラ値やスカラ値と
|
||||
エンティティの組み合わせを返してもよいです。</para>
|
||||
|
||||
<programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
|
||||
.addScalar("maxWeight", Hibernate.DOUBLE);
|
||||
.uniqueResult();]]></programlisting>
|
||||
|
||||
<para>代わりに、hbmファイルにリザルトセットのマッピング情報を記述し、
|
||||
クエリで使用することができます。</para>
|
||||
|
||||
<programlisting><![CDATA[List cats = sess.createSQLQuery(
|
||||
"select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
|
||||
)
|
||||
.setResultSetMapping("catAndKitten")
|
||||
.list();]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-aliasreferences">
|
||||
<title>別名とプロパティの参照</title>
|
||||
<para>上記の <literal>{cat.*}</literal> という表記は、「すべてのプロパティ」を表す省略形です。
|
||||
代わりに、明示的にカラムを列挙してもよいですが、
|
||||
この場合は、Hibernateに各プロパティに対応するSQL列の別名を挿入させるべきでしょう。
|
||||
列の別名のためのプレースホルダは、テーブルの別名によって修飾されたプロパティ名です。
|
||||
下記の例では、別のテーブル(<literal>cat_log</literal>)から
|
||||
マッピングメタデータで定義された <literal>Cat</literal> を復元します。
|
||||
もし好むなら、where節の中でさえ、プロパティの別名を使えることに気をつけてください。</para>
|
||||
|
||||
<para>名前付きクエリに対して <literal>{}</literal> 構文は必須では <emphasis>ない</emphasis> です。
|
||||
<xref linkend="querysql-namedqueries"/> を参照してください。</para>
|
||||
|
||||
<programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
|
||||
"cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
|
||||
"cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
|
||||
"from cat_log cat where {cat.mate} = :catId"
|
||||
|
||||
List loggedCats = sess.createSQLQuery(sql)
|
||||
.addEntity("cat", Cat.class)
|
||||
.setLong("catId", catId)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para><emphasis>注意:</emphasis> もし明示的に各プロパティを列挙するなら、
|
||||
クラス <emphasis>とサブクラス</emphasis> のすべてのプロパティを含めなければなりません!</para>
|
||||
|
||||
|
||||
<para>別名に挿入できるものを下表に示します。
|
||||
注意:下表の別名は一例です。
|
||||
それぞれの別名は一意であり、使用する際にはおそらく異なる名前を持ちます。</para>
|
||||
|
||||
<table frame="topbot" id="aliasinjection-summary">
|
||||
<title>別名に挿入する名前</title>
|
||||
|
||||
<tgroup cols="4">
|
||||
<colspec colwidth="1*" />
|
||||
|
||||
<colspec colwidth="1*" />
|
||||
|
||||
<colspec colwidth="2.5*" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>説明</entry>
|
||||
<entry>構文</entry>
|
||||
<entry>例</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>単純なプロパティ</entry>
|
||||
<entry><literal>{[aliasname].[propertyname]}</literal></entry>
|
||||
<entry><literal>A_NAME as {item.name}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>複合プロパティ</entry>
|
||||
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
|
||||
<entry><literal>CURRENCY as {item.amount.currency}, VALUE as {item.amount.value}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>エンティティのクラスを識別する値</entry>
|
||||
<entry><literal>{[aliasname].class}</literal></entry>
|
||||
<entry><literal>DISC as {item.class}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>エンティティの全プロパティ</entry>
|
||||
<entry><literal>{[aliasname].*}</literal></entry>
|
||||
<entry><literal>{item.*}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションのキー</entry>
|
||||
<entry><literal>{[aliasname].key}</literal></entry>
|
||||
<entry><literal>ORGID as {coll.key}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションのID</entry>
|
||||
<entry><literal>{[aliasname].id}</literal></entry>
|
||||
<entry><literal>EMPID as {coll.id}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションの要素</entry>
|
||||
<entry><literal>{[aliasname].element}</literal></entry>
|
||||
<entry><literal>XID as {coll.element}</literal></entry>
|
||||
<entry></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションの要素のプロパティ</entry>
|
||||
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
|
||||
<entry><literal>NAME as {coll.element.name}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションの要素の全プロパティ</entry>
|
||||
<entry><literal>{[aliasname].element.*}</literal></entry>
|
||||
<entry><literal>{coll.element.*}</literal></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>コレクションの全プロパティ</entry>
|
||||
<entry><literal>{[aliasname].*}</literal></entry>
|
||||
<entry><literal>{coll.*}</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-namedqueries" revision="3">
|
||||
<title>名前付きSQLクエリ</title>
|
||||
|
||||
<para>名前付きSQLクエリはマッピングドキュメントで定義することができ、
|
||||
名前付きHQLクエリと全く同じ方法で呼ぶことができます。
|
||||
この場合、<literal>addEntity()</literal> を呼び出す必要は <emphasis>ない</emphasis> です。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="persons">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
SELECT person.NAME AS {person.name},
|
||||
person.AGE AS {person.age},
|
||||
person.SEX AS {person.sex}
|
||||
FROM PERSON person
|
||||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[List people = sess.getNamedQuery("persons")
|
||||
.setString("namePattern", namePattern)
|
||||
.setMaxResults(50)
|
||||
.list();]]></programlisting>
|
||||
|
||||
<para>関連を結合するためとコレクションを初期化するクエリを定義するために、それぞれ
|
||||
<literal><return-join></literal> と <literal><load-collection></literal>
|
||||
要素を使います。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="personsWith">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
<return-join alias="address" property="person.mailingAddress"/>
|
||||
SELECT person.NAME AS {person.name},
|
||||
person.AGE AS {person.age},
|
||||
person.SEX AS {person.sex},
|
||||
adddress.STREET AS {address.street},
|
||||
adddress.CITY AS {address.city},
|
||||
adddress.STATE AS {address.state},
|
||||
adddress.ZIP AS {address.zip}
|
||||
FROM PERSON person
|
||||
JOIN ADDRESS adddress
|
||||
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
||||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>名前付きSQLクエリはスカラ値を返すこともできます。
|
||||
<literal><return-scalar></literal> 要素を使って、
|
||||
列の別名とHibernateの型を宣言しなければなりません。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return-scalar column="name" type="string"/>
|
||||
<return-scalar column="age" type="long"/>
|
||||
SELECT p.NAME AS name,
|
||||
p.AGE AS age,
|
||||
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
|
||||
<para>リザルトセットのマッピング情報を <literal><resultset></literal>
|
||||
に外出しすることができます。
|
||||
複数の名前付きクエリで再利用したり、<literal>setResultSetMapping()</literal>
|
||||
APIを通して再利用したりできます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<resultset name="personAddress">
|
||||
<return alias="person" class="eg.Person"/>
|
||||
<return-join alias="address" property="person.mailingAddress"/>
|
||||
</resultset>
|
||||
|
||||
<sql-query name="personsWith" resultset-ref="personAddress">
|
||||
SELECT person.NAME AS {person.name},
|
||||
person.AGE AS {person.age},
|
||||
person.SEX AS {person.sex},
|
||||
adddress.STREET AS {address.street},
|
||||
adddress.CITY AS {address.city},
|
||||
adddress.STATE AS {address.state},
|
||||
adddress.ZIP AS {address.zip}
|
||||
FROM PERSON person
|
||||
JOIN ADDRESS adddress
|
||||
ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
|
||||
WHERE person.NAME LIKE :namePattern
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<sect2 id="propertyresults">
|
||||
<title>列と列の別名を明示的に指定するために return-property を使う</title>
|
||||
|
||||
<para>別名を挿入するために <literal>{}</literal> 構文を使う代わりに、
|
||||
<literal><return-property></literal> を使い、
|
||||
どの列の別名を使うのかを明示できます。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="mySqlQuery">
|
||||
<return alias="person" class="eg.Person">
|
||||
<return-property name="name" column="myName"/>
|
||||
<return-property name="age" column="myAge"/>
|
||||
<return-property name="sex" column="mySex"/>
|
||||
</return>
|
||||
SELECT person.NAME AS myName,
|
||||
person.AGE AS myAge,
|
||||
person.SEX AS mySex,
|
||||
FROM PERSON person WHERE person.NAME LIKE :name
|
||||
</sql-query>
|
||||
]]></programlisting>
|
||||
|
||||
<para><literal><return-property></literal> は複数の列も扱えます。
|
||||
これは、複数列のプロパティをきめ細かく制御できないという、
|
||||
<literal>{}</literal> 構文の制限を解決します。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
|
||||
<return alias="emp" class="Employment">
|
||||
<return-property name="salary">
|
||||
<return-column name="VALUE"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
<return-property name="endDate" column="myEndDate"/>
|
||||
</return>
|
||||
SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
|
||||
STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
|
||||
REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT
|
||||
WHERE EMPLOYER = :id AND ENDDATE IS NULL
|
||||
ORDER BY STARTDATE ASC
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>この例では、挿入のための <literal>{}</literal> 構文といっしょに、
|
||||
<literal><return-property></literal> を使っていることに注意してください。
|
||||
列とプロパティをどのように参照するかを選べます。</para>
|
||||
|
||||
<para>マッピングに discriminator が含まれている場合、
|
||||
discriminator の列を指定するために、<return-discriminator>
|
||||
を使わなければなりません。</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="sp_query" revision="1">
|
||||
<title>問い合わせするためにストアドプロシージャを使う</title>
|
||||
|
||||
<para>Hibernateはバージョン3から、ストアドプロシージャとストアド関数経由の問い合わせが
|
||||
サポートされました。
|
||||
以降の文書の多くは、両方に当てはまります。
|
||||
ストアドプロシージャやストアド関数をHibernateで使うためには、
|
||||
1番目の出力パラメータとしてリザルトセットを返さなければなりません。
|
||||
Oracle 9(もしくはそれ以上のバージョン)のストアドプロシージャの例を以下に示します。</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
|
||||
RETURN SYS_REFCURSOR
|
||||
AS
|
||||
st_cursor SYS_REFCURSOR;
|
||||
BEGIN
|
||||
OPEN st_cursor FOR
|
||||
SELECT EMPLOYEE, EMPLOYER,
|
||||
STARTDATE, ENDDATE,
|
||||
REGIONCODE, EID, VALUE, CURRENCY
|
||||
FROM EMPLOYMENT;
|
||||
RETURN st_cursor;
|
||||
END;]]></programlisting>
|
||||
|
||||
<para>Hibernateでこのクエリを使うためには、
|
||||
名前付きクエリでマッピングする必要があります。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
|
||||
<return alias="emp" class="Employment">
|
||||
<return-property name="employee" column="EMPLOYEE"/>
|
||||
<return-property name="employer" column="EMPLOYER"/>
|
||||
<return-property name="startDate" column="STARTDATE"/>
|
||||
<return-property name="endDate" column="ENDDATE"/>
|
||||
<return-property name="regionCode" column="REGIONCODE"/>
|
||||
<return-property name="id" column="EID"/>
|
||||
<return-property name="salary">
|
||||
<return-column name="VALUE"/>
|
||||
<return-column name="CURRENCY"/>
|
||||
</return-property>
|
||||
</return>
|
||||
{ ? = call selectAllEmployments() }
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>注意:今のところ、ストアドプロシージャはスカラとエンティティを返すのみです。
|
||||
<literal><return-join></literal> と <literal><load-collection></literal>
|
||||
はサポートされていません。</para>
|
||||
|
||||
<sect3 id="querysql-limits-storedprocedures" revision="1">
|
||||
<title>ストアドプロシージャを使う上でのルールと制限</title>
|
||||
|
||||
<para>Hibernateでストアドプロシージャや関数を使うためには、
|
||||
そのプロシージャはいくつかのルールに準拠する必要があります。
|
||||
ルールに準拠していないプロシージャは、Hibernateで使うことはできません。
|
||||
それでも、準拠していないプロシージャを使いたいのであれば、
|
||||
<literal>session.connection()</literal> を通じて実行しなければなりません。
|
||||
ルールはデータベースごとに異なります。
|
||||
ストアドプロシージャのセマンティックスとシンタックスは、
|
||||
データベースベンダごとに異なるためです。</para>
|
||||
|
||||
<para><literal>setFirstResult()/setMaxResults()</literal> を使って、
|
||||
ストアドプロシージャクエリをページ分けすることはできません。</para>
|
||||
|
||||
<para>推奨する呼び出し方は、標準であるSQL92に従うことです。
|
||||
<literal>{ ? = call functionName(<parameters>) }</literal> や
|
||||
<literal>{ ? = call procedureName(<parameters>) }</literal> です。
|
||||
ネイティブな呼び出し構文はサポートされていません。</para>
|
||||
|
||||
<para>Oracleには下記のルールが適用されます。</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>関数はリザルトセットを返さなければなりません。
|
||||
プロシージャの第一引数はリザルトセットを返すため、
|
||||
<literal>OUT</literal> でなければなりません。
|
||||
Oracle 9と10では、<literal>SYS_REFCURSOR</literal> を使うことによってできます。
|
||||
Oracleでは <literal>REF CURSOR</literal> 型を定義する必要があります。
|
||||
Oracleの文献を参照してください。</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>SybaseとMS SQLサーバーに適用されるルールを下記に示します。</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>プロシージャはリザルトセットを返さなければなりません。
|
||||
サーバーは複数のリザルトセットと更新カウントを返しますが、
|
||||
Hibernateは1つ目のリザルトセットだけを返すことに注意してください。
|
||||
その他はすべて捨てられます。</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>プロシージャの中で <literal>SET NOCOUNT ON</literal> を有効にできれば、
|
||||
おそらく効率がよくなるでしょう。
|
||||
しかし、これは必要条件ではありません。</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect3>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-cud">
|
||||
<title>作成、更新、削除のためのカスタムSQL</title>
|
||||
|
||||
<para>Hibernate3は作成、更新、削除処理のためのカスタムSQL文を使用できます。
|
||||
クラスとコレクションの永続化機構は、コンフィグレーション時に生成された文字列
|
||||
(insertsql、deletesql、updatesqlなど)のセットをすでに保持しています。
|
||||
これらの文字列より、
|
||||
<literal><sql-insert></literal>、
|
||||
<literal><sql-delete></literal>、
|
||||
<literal><sql-update></literal> というマッピングタグが優先されます。</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
|
||||
<sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
|
||||
<sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>SQLを直接データベースで実行するため、好みの方言を自由に使用できます。
|
||||
データベース独自のSQLを使えば、当然マッピングのポータビリティが下がります。</para>
|
||||
|
||||
<para><literal>callable</literal> 属性をセットすれば、
|
||||
ストアドプロシージャを使用できます。</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
|
||||
<sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
|
||||
<sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>今のところ、位置パラメータの順番はとても重要です。
|
||||
すなわち、Hibernateが期待する順序でなければなりません。</para>
|
||||
|
||||
<para><literal>org.hiberante.persister.entity</literal> レベルのデバッグログを
|
||||
有効にすることによって、期待される順番を確かめられます。
|
||||
このレベルを有効にすることにより、エンティティの作成、更新、削除などで
|
||||
使用される静的なSQLが出力されます。
|
||||
(期待される順序を確認するためには、Hibernateが生成する静的なSQLをオーバーライドする
|
||||
カスタムSQLをマッピングファイルに含めないことを忘れないでください。)</para>
|
||||
|
||||
<para>ストアドプロシージャは挿入/更新/削除された行数を返す必要があります
|
||||
(読み込みの場合は、返さないよりは返す方がよいです)。
|
||||
実行時にHibernateがSQL文の成功をチェックするからです。
|
||||
Hibernateは、CUD処理のための数値の出力パラメータとして、
|
||||
SQL文の最初のパラメータをいつも記録します。</para>
|
||||
|
||||
<programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
|
||||
RETURN NUMBER IS
|
||||
BEGIN
|
||||
|
||||
update PERSON
|
||||
set
|
||||
NAME = uname,
|
||||
where
|
||||
ID = uid;
|
||||
|
||||
return SQL%ROWCOUNT;
|
||||
|
||||
END updatePerson;]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querysql-load">
|
||||
<title>ロードのためのカスタムSQL</title>
|
||||
|
||||
<para>エンティティを読み込むための独自のSQL(もしくはHQL)クエリも宣言できます。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
||||
SELECT NAME AS {pers.name}, ID AS {pers.id}
|
||||
FROM PERSON
|
||||
WHERE ID=?
|
||||
FOR UPDATE
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>これは、まさに(以前議論した)名前付きクエリの宣言です。
|
||||
この名前付きクエリをクラスのマッピングから参照できます。</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Person">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<loader query-ref="person"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
|
||||
<para>これはストアドプロシージャでさえも動作します。</para>
|
||||
|
||||
<para>次のように、コレクションをロードするためのクエリさえ定義してよいです。</para>
|
||||
|
||||
<programlisting><![CDATA[<set name="employments" inverse="true">
|
||||
<key/>
|
||||
<one-to-many class="Employment"/>
|
||||
<loader query-ref="employments"/>
|
||||
</set>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="employments">
|
||||
<load-collection alias="emp" role="Person.employments"/>
|
||||
SELECT {emp.*}
|
||||
FROM EMPLOYMENT emp
|
||||
WHERE EMPLOYER = :id
|
||||
ORDER BY STARTDATE ASC, EMPLOYEE ASC
|
||||
</sql-query>]]></programlisting>
|
||||
|
||||
<para>次のように、結合フェッチによりコレクションをロードする
|
||||
エンティティローダーを定義できます。</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person"/>
|
||||
<return-join alias="emp" property="pers.employments"/>
|
||||
SELECT NAME AS {pers.*}, {emp.*}
|
||||
FROM PERSON pers
|
||||
LEFT OUTER JOIN EMPLOYMENT emp
|
||||
ON pers.ID = emp.PERSON_ID
|
||||
WHERE ID=?
|
||||
</sql-query>]]></programlisting>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
|
@ -0,0 +1,634 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="toolsetguide" revision="2">
|
||||
<title>Toolset Guide
|
||||
|
||||
ツールセットガイド
|
||||
</title>
|
||||
|
||||
<para>
|
||||
Hibernateを使ったラウンドトリップエンジニアリングは、
|
||||
Eclipseプラグインやコマンドラインツール、もちろんAntタスクを使うことで可能です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Hibernate Tools</emphasis> は現在、既存データベースのリバースエンジニアリングのAntタスクに加えて、EclipseIDEのプラグインを含みます。
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<emphasis>マッピングエディタ:</emphasis>
|
||||
HibernateのXMLマッピングファイル用のエディタで、
|
||||
自動補完と構文強調表示をサポートしています。クラス名やプロパティ/フィールド名に対する自動補完もサポートし、
|
||||
通常のXMLエディタよりも強力です。
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Console:</emphasis>
|
||||
コンソールはエクリプスの新しいビューです。
|
||||
コンソールコンフィギュレーションのツリーオーバービューに加えて、永続クラスとその関連の相互作用ビューも得られます。
|
||||
データベースにHQLを実行し、結果を直接エクリプス上で見ることができます。
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>開発ウィザード</emphasis>
|
||||
HibernateのEclipseツールはいくつかのウィザードを提供します。
|
||||
ウィザードを使ってHibernateの設定ファイル(cfg.xml)をすばやく生成したり、
|
||||
既存のデータベーススキーマをPOJOのソースファイルとHibernateのマッピングファイルへと、
|
||||
完全にリバースエンジニアリングすることができます。
|
||||
リバースエンジニアリングウィザードはカスタマイズ可能なテンプレートをサポートします。
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<emphasis>Ant Tasks:</emphasis>
|
||||
</para></listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
より詳しい情報は <emphasis>Hibernate Tools</emphasis> パッケージとそのドキュメントを参照してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
しかし、Hibernateのメインパッケージは <emphasis>SchemaExport</emphasis> 、
|
||||
別名 <literal>hbm2ddl</literal> も含みます(Hibernate内でオンザフライで使用できます)。
|
||||
</para>
|
||||
|
||||
<sect1 id="toolsetguide-s1" revision="2">
|
||||
<title>スキーマの自動生成</title>
|
||||
|
||||
<para>
|
||||
DDLはHibernateユーティリティによりマッピングファイルから生成することができます。
|
||||
生成されたスキーマはエンティティやコレクションのテーブルに対する参照整合性制約(主キーと外部キー)を含みます。
|
||||
テーブルとシーケンスはマッピングする識別子ジェネレータに対して生成されます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
DDLはベンダー依存なので、このツールを使うときは、<literal>hibernate.dialect</literal>
|
||||
プロパティでSQLの <literal>方言</literal> を指定 <emphasis>しなければなりません</emphasis> 。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
まず、生成されるスキーマを改善するように、マッピングファイルをカスタマイズしてください。
|
||||
</para>
|
||||
|
||||
<sect2 id="toolsetguide-s1-2" revision="3">
|
||||
<title>スキーマのカスタマイズ</title>
|
||||
|
||||
<para>
|
||||
多くのHibernateのマッピング要素では、オプションの <literal>length</literal> という名の属性を定義しています。
|
||||
この属性でカラム長を設定することができます(またはNUMERIC/DECIMAL型のデータの精度を設定できます)。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>not-null</literal> 属性(テーブルのカラムへ <literal>NOT NULL</literal> 制約を生成する)と
|
||||
<literal>unique</literal> 属性(テーブルのカラムへ <literal>UNIQUE</literal> 制約を生成する)が設定できるタグもあります。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="bar" column="barId" not-null="true"/>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<element column="serialNumber" type="long" not-null="true" unique="true"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>unique-key</literal> 属性はカラムをグループ化して一つのキー制約にするために使われます。
|
||||
現在、<literal>unique-key</literal> 属性で指定された値は制約の指定には <emphasis>使われず</emphasis> 、
|
||||
マッピングファイルでカラムをグループ化することにのみ使われます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/>
|
||||
<property name="employeeId" unique-key="OrgEmployee"/>]]></programlisting>
|
||||
|
||||
|
||||
|
||||
<para>
|
||||
<literal>index</literal> 属性はマッピングするカラムを使って生成したインデックスの名前を指定します。
|
||||
複数カラムを1つのインデックスにグループ化できます。単に、同じインデックス名を指定するだけです。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="lastName" index="CustName"/>
|
||||
<property name="firstName" index="CustName"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>foreign-key</literal> 属性は、生成された外部キー制約の名前をオーバーライドするために使用できます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>]]></programlisting>
|
||||
|
||||
<para>
|
||||
多くのマッピング要素は、子 <literal><column></literal> 要素を記述できます。これは複数カラム型のマッピングには特に有用です。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="name" type="my.customtypes.Name"/>
|
||||
<column name="last" not-null="true" index="bar_idx" length="30"/>
|
||||
<column name="first" not-null="true" index="bar_idx" length="20"/>
|
||||
<column name="initial"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>default</literal> 属性はカラムのデフォルト値を指定します
|
||||
(マッピングしたクラスの新しいインスタンスを保存する前に、
|
||||
マッピングしたプロパティへ同じ値を代入すべきです)。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="credits" type="integer" insert="false">
|
||||
<column name="credits" default="10"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<version name="version" type="integer" insert="false">
|
||||
<column name="version" default="0"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>sql-type</literal> 属性で、デフォルトのHibernate型からSQLのデータ型へのマッピングをオーバーライドできます。
|
||||
</para>
|
||||
|
||||
|
||||
<programlisting><![CDATA[<property name="balance" type="float">
|
||||
<column name="balance" sql-type="decimal(13,3)"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
|
||||
<para>
|
||||
<literal>check</literal> 属性でチェック制約を指定することができます。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<property name="foo" type="integer">
|
||||
<column name="foo" check="foo > 10"/>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
|
||||
...
|
||||
<property name="bar" type="float"/>
|
||||
</class>]]></programlisting>
|
||||
|
||||
|
||||
<table frame="topbot" id="schemattributes-summary" revision="2">
|
||||
<title>まとめ</title>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="1*"/>
|
||||
<colspec colwidth="1*"/>
|
||||
<colspec colwidth="2.5*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>属性</entry>
|
||||
<entry>値</entry>
|
||||
<entry>説明</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>length</literal></entry>
|
||||
<entry>数値</entry>
|
||||
<entry>カラムの長さ</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>precision</literal></entry>
|
||||
<entry>数値</entry>
|
||||
<entry>カラムのDECIMAL型の精度(precision)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>scale</literal></entry>
|
||||
<entry>数値</entry>
|
||||
<entry>カラムのDECIMAL型のスケール(scale)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>not-null</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>カラムがnull値を取らないことを指定します
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique</literal></entry>
|
||||
<entry><literal>true|false</literal></entry>
|
||||
<entry>カラムがユニーク制約を持つことを指定します
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>index</literal></entry>
|
||||
<entry><literal>インデックス名</literal> </entry>
|
||||
<entry>(複数カラムの)インデックスの名前を指定します
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>unique-key</literal></entry>
|
||||
<entry><literal>ユニークキー名</literal></entry>
|
||||
<entry>複数カラムのユニーク制約の名前を指定します
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>foreign-key</literal></entry>
|
||||
<entry><literal>外部キー名</literal></entry>
|
||||
<entry>
|
||||
<one-to-one>、<many-to-one>、<many-to-many>マッピング要素を使って、
|
||||
関連に対し生成された外部キー制約の名前を指定します。
|
||||
<literal>SchemaExport</literal> は <literal>inverse="true"</literal> 側を考慮しないことに注意してください。
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>sql-type</literal></entry>
|
||||
<entry><literal>SQLのカラム型</literal></entry>
|
||||
|
||||
<entry>
|
||||
デフォルトのカラム型をオーバーライドします( <literal><column></literal> 要素の属性のみ)
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>default</literal></entry>
|
||||
<entry>SQL式</entry>
|
||||
|
||||
<entry>
|
||||
カラムのデフォルト値を指定します
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>check</literal></entry>
|
||||
<entry>SQL式</entry>
|
||||
|
||||
<entry>
|
||||
カラムかテーブルにSQLのチェック制約を作成します
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
<literal><comment></literal> 要素で生成するスキーマにコメントを指定することができます。
|
||||
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Customer" table="CurCust">
|
||||
<comment>Current customers only</comment>
|
||||
...
|
||||
</class>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<property name="balance">
|
||||
<column name="bal">
|
||||
<comment>Balance in USD</comment>
|
||||
</column>
|
||||
</property>]]></programlisting>
|
||||
|
||||
<para>
|
||||
これにより、生成したDDLに <literal>comment on table</literal> や <literal>comment on column</literal> 文が書かれます。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-3" revision="2">
|
||||
<title>ツールの実行</title>
|
||||
|
||||
<para>
|
||||
<literal>SchemaExport</literal> は標準出力に対してDDLスクリプトを書き出し、DDL文を実行したりもします。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>java -cp </literal> <emphasis>hibernate_classpaths</emphasis>
|
||||
<literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis>
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title> <literal>SchemaExport</literal> Command Line Options
|
||||
|
||||
<literal>SchemaExport</literal> のコマンドラインオプション
|
||||
</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>オプション</entry>
|
||||
<entry>説明</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry> <literal>--quiet</literal> </entry>
|
||||
<entry>スクリプトを標準出力に出力しません</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--drop</literal> </entry>
|
||||
<entry>テーブルの削除だけを行います</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--create</literal> </entry>
|
||||
<entry>テーブルの生成のみを行います。
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--text</literal> </entry>
|
||||
<entry>データベースにエクスポートしません</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--output=my_schema.ddl</literal> </entry>
|
||||
<entry> DDLスクリプトをファイルに出力します</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
|
||||
<entry> <literal>NamingStrategy</literal> を選択します
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>--config=hibernate.cfg.xml</literal> </entry>
|
||||
<entry>XMLファイルからHibernateの定義情報を読み込みます</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--properties=hibernate.properties</literal> </entry>
|
||||
<entry>ファイルからデータベースプロパティを読み込みます</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--format</literal> </entry>
|
||||
<entry>スクリプト内に生成するSQLを読みやすいようにフォーマットします</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--delimiter=x</literal> </entry>
|
||||
<entry>スクリプトの行区切り文字を設定します</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
アプリケーションに <literal>SchemaExport</literal> を組み込むこともできます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
new SchemaExport(cfg).create(false, true);]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="toolsetguide-s1-4">
|
||||
<title>プロパティ</title>
|
||||
|
||||
<para>
|
||||
次のように、データベースのプロパティを指定することができます。
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>-D</literal> <emphasis><property></emphasis> を使って、システムプロパティとして
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>hibernate.properties</literal> ファイル内で
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para> <literal>--properties</literal> を使って指定したプロパティファイル内で
|
||||
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
必要なプロパティは以下のものです:
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title>SchemaExportコネクションプロパティ</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>プロパティ名
|
||||
</entry>
|
||||
<entry>説明
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry> <literal>hibernate.connection.driver_class</literal> </entry>
|
||||
<entry>jdbcのドライバークラス
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>hibernate.connection.url</literal> </entry>
|
||||
<entry>jdbcのurl
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>hibernate.connection.username</literal> </entry>
|
||||
<entry>データベースのユーザ
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>hibernate.connection.password</literal> </entry>
|
||||
<entry>ユーザパスワード
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>hibernate.dialect</literal> </entry>
|
||||
<entry>データベース方言
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-5">
|
||||
<title>Antを使用する</title>
|
||||
|
||||
<para>
|
||||
Antのビルドスクリプトから <literal>SchemaExport</literal> を呼び出すことができます。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="schemaexport">
|
||||
<taskdef name="schemaexport"
|
||||
classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
|
||||
classpathref="class.path"/>
|
||||
|
||||
<schemaexport
|
||||
properties="hibernate.properties"
|
||||
quiet="no"
|
||||
text="no"
|
||||
drop="no"
|
||||
delimiter=";"
|
||||
output="schema-export.sql">
|
||||
<fileset dir="src">
|
||||
<include name="**/*.hbm.xml"/>
|
||||
</fileset>
|
||||
</schemaexport>
|
||||
</target>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-6" revision="2">
|
||||
<title>インクリメンタルなスキーマ更新
|
||||
</title>
|
||||
|
||||
<para>
|
||||
<literal>SchemaUpdate</literal> ツールは既存のスキーマをインクリメンタルに更新します。
|
||||
<literal>SchemaUpdate</literal> はJDBCのメタデータAPIに強く依存します。
|
||||
そのため、すべてのJDBCドライバでうまくいくとは限らないことに注意してください。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>java -cp </literal> <emphasis>hibernate_classpaths</emphasis>
|
||||
<literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>options mapping_files</emphasis>
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title> <literal>SchemaUpdate</literal> のコマンドライン・オプション</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>オプション</entry>
|
||||
<entry>説明</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry> <literal>--quiet</literal> </entry>
|
||||
<entry>標準出力にスクリプトを出力しません</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--text</literal> </entry>
|
||||
<entry>データベースにスクリプトをエクスポートしません
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
|
||||
<entry><literal>NamingStrategy</literal> を選択します。
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--properties=hibernate.properties</literal> </entry>
|
||||
<entry>ファイルからデータベースプロパティを読み込みます
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
|
||||
<entry><literal>.cfg.xml</literal> ファイルを指定します
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
アプリケーションに <literal>SchemaUpdate</literal> を組み込むことができます。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
new SchemaUpdate(cfg).execute(false);]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="toolsetguide-s1-7">
|
||||
<title>インクリメンタルなスキーマ更新に対するAntの使用</title>
|
||||
|
||||
<para>
|
||||
Antスクリプトから <literal>SchemaUpdate</literal> を呼び出すことができます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="schemaupdate">
|
||||
<taskdef name="schemaupdate"
|
||||
classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
|
||||
classpathref="class.path"/>
|
||||
|
||||
<schemaupdate
|
||||
properties="hibernate.properties"
|
||||
quiet="no">
|
||||
<fileset dir="src">
|
||||
<include name="**/*.hbm.xml"/>
|
||||
</fileset>
|
||||
</schemaupdate>
|
||||
</target>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-8" revision="1">
|
||||
<title>Schema validation</title>
|
||||
|
||||
<para>
|
||||
<literal>SchemaValidator</literal> ツールは、既存のデータベーススキーマと作成したマッピングドキュメントが"一致する"ことを検証します。 <literal>SchemaValidator</literal> はJDBCのメタデータAPIに強く依存することに注意してください。そのため、すべてのJDBCドライバーで作動するものではありません。このツールはテスト時に非常に有用です。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<literal>java -cp </literal> <emphasis>hibernate_classpaths</emphasis>
|
||||
<literal>org.hibernate.tool.hbm2ddl.SchemaValidator</literal> <emphasis>options mapping_files</emphasis>
|
||||
</para>
|
||||
|
||||
<table frame="topbot">
|
||||
<title> <literal>SchemaValidator</literal> のコマンドライン・オプション
|
||||
</title>
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1.5*"/>
|
||||
<colspec colwidth="2*"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry>オプション</entry>
|
||||
<entry>説明</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry> <literal>--naming=eg.MyNamingStrategy</literal> </entry>
|
||||
<entry><literal>NamingStrategy</literal> を選択します
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--properties=hibernate.properties</literal> </entry>
|
||||
<entry>ファイルからデータベースのプロパティを読み込みます
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry> <literal>--config=hibernate.cfg.xml</literal> </entry>
|
||||
<entry><literal>.cfg.xml</literal> ファイルを指定します
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
<literal>SchemaValidator</literal> をアプリケーションに組み込むことが出来ます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Configuration cfg = ....;
|
||||
new SchemaValidator(cfg).validate();]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="toolsetguide-s1-9">
|
||||
<title>スキーマのバリデーションにAntを使用します</title>
|
||||
|
||||
<para>
|
||||
Antスクリプトから <literal>SchemaValidator</literal> を呼び出せます:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<target name="schemavalidate">
|
||||
<taskdef name="schemavalidator"
|
||||
classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask"
|
||||
classpathref="class.path"/>
|
||||
|
||||
<schemavalidator
|
||||
properties="hibernate.properties">
|
||||
<fileset dir="src">
|
||||
<include name="**/*.hbm.xml"/>
|
||||
</fileset>
|
||||
</schemaupdate>
|
||||
</target>]]></programlisting>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
<chapter id="xml">
|
||||
<title>XMLマッピング</title>
|
||||
|
||||
<para><emphasis>XMLマッピングはHibernate3.0では試験的な機能であり、非常に活動的に開発中です。</emphasis></para>
|
||||
|
||||
<sect1 id="xml-intro" revision="1">
|
||||
<title>XMLデータでの作業</title>
|
||||
|
||||
<para>
|
||||
Hibernateでは永続性のPOJOを使って作業するのとほぼ同じようなやり方で、
|
||||
永続性のXMLデータを使って作業できます。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HibernateはXMLツリーを操作するためのAPIとしてdom4jをサポートしています。
|
||||
データベースからdom4jのツリーを復元するクエリを書くことができ、
|
||||
ツリーに対して行った修正は自動的にデータベースと同期されます。
|
||||
|
||||
またXMLドキュメントを取得することができ、dom4jを使ってドキュメントをパースし、
|
||||
Hibernateの任意の基本操作を使ってデータベースへ書き込むことができます。:
|
||||
つまり、<literal>persist(), saveOrUpdate(), merge(), delete(), replicate()</literal>
|
||||
操作です(マージはまだサポートしていません)。
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
データのインポート/エクスポート、
|
||||
JMSによるエンティティデータの外部化やSOAP、XSLTベースのレポートなど、
|
||||
この機能には多くの用途があります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
単一のマッピングは、クラスのプロパティとXMLドキュメントのノードを
|
||||
同時にデータベースへマッピングするために使うことができます。
|
||||
またマッピングするクラスがなければ、
|
||||
XMLだけをマッピングするために使うことができます。
|
||||
|
||||
</para>
|
||||
|
||||
<sect2 id="xml-intro-mapping">
|
||||
<title>XMLとクラスのマッピングを同時に指定する</title>
|
||||
|
||||
<para>
|
||||
これはPOJOとXMLを同時にマッピングする例です。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Account"
|
||||
table="ACCOUNTS"
|
||||
node="account">
|
||||
|
||||
<id name="accountId"
|
||||
column="ACCOUNT_ID"
|
||||
node="@id"/>
|
||||
|
||||
<many-to-one name="customer"
|
||||
column="CUSTOMER_ID"
|
||||
node="customer/@id"
|
||||
embed-xml="false"/>
|
||||
|
||||
<property name="balance"
|
||||
column="BALANCE"
|
||||
node="balance"/>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="xml-onlyxml">
|
||||
<title>XMLマッピングだけを指定する</title>
|
||||
|
||||
<para>
|
||||
これはPOJOクラスがないマッピングの例です。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class entity-name="Account"
|
||||
table="ACCOUNTS"
|
||||
node="account">
|
||||
|
||||
<id name="id"
|
||||
column="ACCOUNT_ID"
|
||||
node="@id"
|
||||
type="string"/>
|
||||
|
||||
<many-to-one name="customerId"
|
||||
column="CUSTOMER_ID"
|
||||
node="customer/@id"
|
||||
embed-xml="false"
|
||||
entity-name="Customer"/>
|
||||
|
||||
<property name="balance"
|
||||
column="BALANCE"
|
||||
node="balance"
|
||||
type="big_decimal"/>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
このマッピングにより、dom4jツリーか、
|
||||
プロパティ名/値の組のグラフ(javaの <literal>Map</literal>)として
|
||||
データにアクセスできます。
|
||||
|
||||
プロパティの名前は、HQLクエリー内で参照できる純粋な論理構造です。
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="xml-mapping" revision="1">
|
||||
<title>XMLマッピングのメタデータ</title>
|
||||
|
||||
<para>
|
||||
多くのHibernateのマッピング要素は <literal>node</literal> 属性が使用できます。
|
||||
これによりXML属性の名前やプロパティやエンティティデータを保持する要素を指定できます。
|
||||
<literal>node</literal> 属性のフォーマットは以下の中の1つでなければなりません。:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"element-name"</literal> - 指定したXML要素へマッピングします
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"@attribute-name"</literal> - 指定したXML属性へマッピングします
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"."</literal> - 親要素へマッピングします
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"element-name/@attribute-name"</literal> -
|
||||
指定したエレメントの指定した属性へマッピングします
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
コレクションと単一の値の関連に対して、
|
||||
おまけの <literal>embed-xml</literal> 属性があります。
|
||||
デフォルトの <literal>embed-xml="true"</literal> と設定した場合、
|
||||
関連するエンティティ(値型のコレクション)のXMLツリーは、
|
||||
直接関連を所有するエンティティのXMLツリー内に埋め込まれます。
|
||||
反対に、<literal>embed-xml="false"</literal> と設定した場合、
|
||||
参照される識別子の値だけが多重度1側の関連に対するXMLに現れ、
|
||||
単純にコレクションはまったく現れなくなります。
|
||||
</para>
|
||||
|
||||
<para>
|
||||
あまりに多くの関連に対して
|
||||
<literal>embed-xml="true"</literal> としたままにするのは注意すべきです。
|
||||
XMLは循環をうまく扱えません。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<class name="Customer"
|
||||
table="CUSTOMER"
|
||||
node="customer">
|
||||
|
||||
<id name="id"
|
||||
column="CUST_ID"
|
||||
node="@id"/>
|
||||
|
||||
<map name="accounts"
|
||||
node="."
|
||||
embed-xml="true">
|
||||
<key column="CUSTOMER_ID"
|
||||
not-null="true"/>
|
||||
<map-key column="SHORT_DESC"
|
||||
node="@short-desc"
|
||||
type="string"/>
|
||||
<one-to-many entity-name="Account"
|
||||
embed-xml="false"
|
||||
node="account"/>
|
||||
</map>
|
||||
|
||||
<component name="name"
|
||||
node="name">
|
||||
<property name="firstName"
|
||||
node="first-name"/>
|
||||
<property name="initial"
|
||||
node="initial"/>
|
||||
<property name="lastName"
|
||||
node="last-name"/>
|
||||
</component>
|
||||
|
||||
...
|
||||
|
||||
</class>]]></programlisting>
|
||||
|
||||
<para>
|
||||
この例では、実際のaccountのデータではなく、
|
||||
accountのidのコレクションを埋め込むことにしました。
|
||||
続きのHQLクエリです:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
|
||||
|
||||
<para>
|
||||
このようなデータセットを返すでしょう
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
<account short-desc="Savings">987632567</account>
|
||||
<account short-desc="Credit Card">985612323</account>
|
||||
<name>
|
||||
<first-name>Gavin</first-name>
|
||||
<initial>A</initial>
|
||||
<last-name>King</last-name>
|
||||
</name>
|
||||
...
|
||||
</customer>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal><one-to-many></literal> マッピングで
|
||||
<literal>embed-xml="true"</literal> と設定した場合、
|
||||
データはこのようになるでしょう。
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<customer id="123456789">
|
||||
<account id="987632567" short-desc="Savings">
|
||||
<customer id="123456789"/>
|
||||
<balance>100.29</balance>
|
||||
</account>
|
||||
<account id="985612323" short-desc="Credit Card">
|
||||
<customer id="123456789"/>
|
||||
<balance>-2370.34</balance>
|
||||
</account>
|
||||
<name>
|
||||
<first-name>Gavin</first-name>
|
||||
<initial>A</initial>
|
||||
<last-name>King</last-name>
|
||||
</name>
|
||||
...
|
||||
</customer>]]></programlisting>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="xml-manipulation" revision="1">
|
||||
<title>XMLデータを扱う</title>
|
||||
|
||||
<para>
|
||||
XMLドキュメントを、アプリケーション内で再読み込みや更新をしてみましょう。
|
||||
以下ではdom4jのセッションを取得することで行います。:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[Document doc = ....;
|
||||
|
||||
Session session = factory.openSession();
|
||||
Session dom4jSession = session.getSession(EntityMode.DOM4J);
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
List results = dom4jSession
|
||||
.createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
|
||||
.list();
|
||||
for ( int i=0; i<results.size(); i++ ) {
|
||||
//add the customer data to the XML document
|
||||
Element customer = (Element) results.get(i);
|
||||
doc.add(customer);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[Session session = factory.openSession();
|
||||
Session dom4jSession = session.getSession(EntityMode.DOM4J);
|
||||
Transaction tx = session.beginTransaction();
|
||||
|
||||
Element cust = (Element) dom4jSession.get("Customer", customerId);
|
||||
for ( int i=0; i<results.size(); i++ ) {
|
||||
Element customer = (Element) results.get(i);
|
||||
//change the customer name in the XML and database
|
||||
Element name = customer.element("name");
|
||||
name.element("first-name").setText(firstName);
|
||||
name.element("initial").setText(initial);
|
||||
name.element("last-name").setText(lastName);
|
||||
}
|
||||
|
||||
tx.commit();
|
||||
session.close();]]></programlisting>
|
||||
|
||||
<para>
|
||||
XMLベースのデータのインポート/エクスポートを実装するために、
|
||||
Hibernateの <literal>replicate()</literal> 操作をこの機能を結びつけるのは
|
||||
極めて有効です。
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
|
@ -1 +1 @@
|
|||
test commit.
|
||||
This translated reference document is v3.1.2.
|
|
@ -0,0 +1,516 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL FO configuration file for the Hibernate
|
||||
Reference Documentation. It defines a custom titlepage and
|
||||
the parameters for the A4 sized PDF printable output.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/fo/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
Custom Title Page
|
||||
################################################### -->
|
||||
|
||||
<xsl:template name="book.titlepage.recto">
|
||||
<fo:block>
|
||||
<fo:table table-layout="fixed" width="175mm">
|
||||
<fo:table-column column-width="175mm"/>
|
||||
<fo:table-body>
|
||||
<fo:table-row>
|
||||
<fo:table-cell text-align="center">
|
||||
<fo:block>
|
||||
<fo:external-graphic src="file:images/hibernate_logo_a.png"/>
|
||||
</fo:block>
|
||||
<fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm">
|
||||
<xsl:value-of select="bookinfo/subtitle"/>
|
||||
</fo:block>
|
||||
<fo:block font-family="Helvetica" font-size="12pt" padding="10mm">
|
||||
Version:
|
||||
<xsl:value-of select="bookinfo/releaseinfo"/>
|
||||
</fo:block>
|
||||
</fo:table-cell>
|
||||
</fo:table-row>
|
||||
</fo:table-body>
|
||||
</fo:table>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Prevent blank pages in output -->
|
||||
<xsl:template name="book.titlepage.before.verso">
|
||||
</xsl:template>
|
||||
<xsl:template name="book.titlepage.verso">
|
||||
</xsl:template>
|
||||
<xsl:template name="book.titlepage.separator">
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Header
|
||||
################################################### -->
|
||||
|
||||
<!-- More space in the center header for long text -->
|
||||
<xsl:attribute-set name="header.content.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$body.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">-5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">-5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Custom Footer
|
||||
################################################### -->
|
||||
|
||||
<!-- This footer prints the Hibernate version number on the left side -->
|
||||
<xsl:template name="footer.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<xsl:variable name="Version">
|
||||
<xsl:choose>
|
||||
<xsl:when test="//releaseinfo">
|
||||
<xsl:text>Hibernate </xsl:text>
|
||||
<xsl:value-of select="//releaseinfo"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$double.sided != 0 and $position = 'left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position = 'center'">
|
||||
<!-- nop -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<fo:page-number/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$pageclass='titlepage'">
|
||||
<!-- nop: other titlepage sequences have no footer -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='left'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'odd' and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided != 0 and $sequence = 'even' and $position='right'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'">
|
||||
<xsl:value-of select="$Version"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Custom Toc Line
|
||||
################################################### -->
|
||||
|
||||
<!-- Improve the TOC. -->
|
||||
<xsl:template name="toc.line">
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="object.id"/>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="label">
|
||||
<xsl:apply-templates select="." mode="label.markup"/>
|
||||
</xsl:variable>
|
||||
|
||||
<fo:block text-align-last="justify"
|
||||
end-indent="{$toc.indent.width}pt"
|
||||
last-line-end-indent="-{$toc.indent.width}pt">
|
||||
<fo:inline keep-with-next.within-line="always">
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
|
||||
<!-- Chapter titles should be bold. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="local-name(.) = 'chapter'">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:if test="$label != ''">
|
||||
<xsl:copy-of select="$label"/>
|
||||
<xsl:value-of select="$autotoc.label.separator"/>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="." mode="titleabbrev.markup"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
<fo:inline keep-together.within-line="always">
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:leader leader-pattern="dots"
|
||||
leader-pattern-width="3pt"
|
||||
leader-alignment="reference-area"
|
||||
keep-with-next.within-line="always"/>
|
||||
<xsl:text> </xsl:text>
|
||||
<fo:basic-link internal-destination="{$id}">
|
||||
<fo:page-number-citation ref-id="{$id}"/>
|
||||
</fo:basic-link>
|
||||
</fo:inline>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Extensions
|
||||
################################################### -->
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<!-- FOP provide only PDF Bookmarks at the moment -->
|
||||
<xsl:param name="fop.extensions">1</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!-- Dot and Whitespace as separator in TOC between Label and Title-->
|
||||
<xsl:param name="autotoc.label.separator" select="'. '"/>
|
||||
|
||||
|
||||
<!--###################################################
|
||||
Paper & Page Size
|
||||
################################################### -->
|
||||
|
||||
<!-- Paper type, no headers on blank pages, no double sided printing -->
|
||||
<xsl:param name="paper.type" select="'A4'"/>
|
||||
<xsl:param name="double.sided">0</xsl:param>
|
||||
<xsl:param name="headers.on.blank.pages">0</xsl:param>
|
||||
<xsl:param name="footers.on.blank.pages">0</xsl:param>
|
||||
|
||||
<!-- Space between paper border and content (chaotic stuff, don't touch) -->
|
||||
<xsl:param name="page.margin.top">5mm</xsl:param>
|
||||
<xsl:param name="region.before.extent">10mm</xsl:param>
|
||||
<xsl:param name="body.margin.top">10mm</xsl:param>
|
||||
|
||||
<xsl:param name="body.margin.bottom">15mm</xsl:param>
|
||||
<xsl:param name="region.after.extent">10mm</xsl:param>
|
||||
<xsl:param name="page.margin.bottom">0mm</xsl:param>
|
||||
|
||||
<xsl:param name="page.margin.outer">18mm</xsl:param>
|
||||
<xsl:param name="page.margin.inner">18mm</xsl:param>
|
||||
|
||||
<!-- No intendation of Titles -->
|
||||
<xsl:param name="title.margin.left">0pc</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Fonts & Styles
|
||||
################################################### -->
|
||||
|
||||
<!-- Default Font size -->
|
||||
<xsl:param name="body.font.master">11</xsl:param>
|
||||
|
||||
<!-- Line height in body text -->
|
||||
<xsl:param name="line-height">1.4</xsl:param>
|
||||
|
||||
<!-- Monospaced fonts are smaller than regular text -->
|
||||
<xsl:attribute-set name="monospace.properties">
|
||||
<xsl:attribute name="font-family">
|
||||
<xsl:value-of select="$monospace.font.family"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="font-size">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Tables
|
||||
################################################### -->
|
||||
|
||||
<!-- The table width should be adapted to the paper size -->
|
||||
<xsl:param name="default.table.width">17.4cm</xsl:param>
|
||||
|
||||
<!-- Some padding inside tables -->
|
||||
<xsl:attribute-set name="table.cell.padding">
|
||||
<xsl:attribute name="padding-left">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">4pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">4pt</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Only hairlines as frame and cell borders in tables -->
|
||||
<xsl:param name="table.frame.border.thickness">0.1pt</xsl:param>
|
||||
<xsl:param name="table.cell.border.thickness">0.1pt</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!-- Label only Sections up to level 2 -->
|
||||
<xsl:param name="local.l10n.xml" select="document('')"/>
|
||||
<l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0">
|
||||
<l:l10n language="en">
|
||||
<l:context name="title-numbered">
|
||||
<l:template name="sect3" text="%t"/>
|
||||
<l:template name="sect4" text="%t"/>
|
||||
<l:template name="sect5" text="%t"/>
|
||||
</l:context>
|
||||
<l:context name="section-xref-numbered">
|
||||
<l:template name="sect3" text="the section called %t"/>
|
||||
<l:template name="sect4" text="the section called %t"/>
|
||||
<l:template name="sect5" text="the section called %t"/>
|
||||
</l:context>
|
||||
</l:l10n>
|
||||
</l:i18n>
|
||||
|
||||
<!--###################################################
|
||||
Titles
|
||||
################################################### -->
|
||||
|
||||
<!-- Chapter title size -->
|
||||
<xsl:attribute-set name="chapter.titlepage.recto.style">
|
||||
<xsl:attribute name="text-align">left</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.8"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Why is the font-size for chapters hardcoded in the XSL FO templates?
|
||||
Let's remove it, so this sucker can use our attribute-set only... -->
|
||||
<xsl:template match="title" mode="chapter.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xsl:use-attribute-sets="chapter.titlepage.recto.style">
|
||||
<xsl:call-template name="component.title">
|
||||
<xsl:with-param name="node" select="ancestor-or-self::chapter[1]"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Sections 1, 2 and 3 titles have a small bump factor and padding -->
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.5"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.25"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level3.properties">
|
||||
<xsl:attribute name="space-before.optimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master * 1.0"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Titles of formal objects (tables, examples, ...) -->
|
||||
<xsl:attribute-set name="formal.title.properties" use-attribute-sets="normal.para.spacing">
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="font-size">
|
||||
<xsl:value-of select="$body.font.master"/>
|
||||
<xsl:text>pt</xsl:text>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="hyphenate">false</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.4em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.6em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.8em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Programlistings
|
||||
################################################### -->
|
||||
|
||||
<!-- Verbatim text formatting (programlistings) -->
|
||||
<xsl:attribute-set name="verbatim.properties">
|
||||
<xsl:attribute name="space-before.minimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.optimum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="border-color">#444444</xsl:attribute>
|
||||
<xsl:attribute name="border-style">solid</xsl:attribute>
|
||||
<xsl:attribute name="border-width">0.1pt</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-right">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-right">0.5em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Shade (background) programlistings -->
|
||||
<xsl:param name="shade.verbatim">1</xsl:param>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#F0F0F0</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- We want to use callouts... -->
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
|
||||
<!-- Place callout bullets at this column in programmlisting.-->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--
|
||||
No, don't use crappy graphics for the callout bullets. This setting
|
||||
enables some weird Unicode rendering for some fancy bullet points
|
||||
in callouts. By default, this can only count to 10 and produces
|
||||
strange results if you ever have more than 10 callouts for one
|
||||
programlisting. We will fix that next.
|
||||
-->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!--
|
||||
Again, fun with DocBook XSL: The callout bullets are rendered in
|
||||
two places: In the programlisting itself and in the list below
|
||||
the listing, with the actual callout text. The rendering in the
|
||||
programlisting is some XSL transformer extension (e.g. a Saxon
|
||||
extension), so we can't change that without messing with the
|
||||
extensions. We only can turn it off by setting this limit to
|
||||
zero, then, a simple bracket style like "(3)" and "(4)" will
|
||||
be used in the programlisting.
|
||||
-->
|
||||
<xsl:param name="callout.unicode.number.limit" select="'0'"></xsl:param>
|
||||
|
||||
<!--
|
||||
The callout bullets in the actual callout list will be rendered
|
||||
with an XSL FO template. The default template is broken: limited to 10
|
||||
nice looking Unicode bullet points and then it doesn't print anything,
|
||||
the fallback doesn't work. We implement our own template, which is not
|
||||
as complicated, more ugly, but works. As always, function is more
|
||||
important than form.
|
||||
-->
|
||||
<xsl:template name="callout-bug">
|
||||
<xsl:param name="conum" select='1'/>
|
||||
<fo:inline
|
||||
color="black"
|
||||
padding-top="0.1em"
|
||||
padding-bottom="0.1em"
|
||||
padding-start="0.2em"
|
||||
padding-end="0.2em"
|
||||
baseline-shift="0.1em"
|
||||
font-family="{$monospace.font.family}"
|
||||
font-weight="bold"
|
||||
font-size="75%">
|
||||
<xsl:text>(</xsl:text>
|
||||
<xsl:value-of select="$conum"/>
|
||||
<xsl:text>)</xsl:text>
|
||||
</fo:inline>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Correct placement of titles for figures and examples. -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
<!-- Format Variable Lists as Blocks (prevents horizontal overflow). -->
|
||||
<xsl:param name="variablelist.as.blocks">1</xsl:param>
|
||||
|
||||
<!-- The horrible list spacing problems, this is much better. -->
|
||||
<xsl:attribute-set name="list.block.spacing">
|
||||
<xsl:attribute name="space-before.optimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.minimum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-before.maximum">0.8em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.optimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.minimum">0.1em</xsl:attribute>
|
||||
<xsl:attribute name="space-after.maximum">0.1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Newer DocBook XSL apparently thinks that some sections are by
|
||||
default "draft" status, and this idiotic thing is by default
|
||||
also set to "maybe", so it spits out a lot of errors with the
|
||||
latest FOP as the XSL/FO styles have references to some draft
|
||||
watermarks, which you actually don't want in the first place.
|
||||
Turn this crap off. If you have to work with the "status"
|
||||
attribute, don't.
|
||||
-->
|
||||
<xsl:param name="draft.mode" select="'no'"/>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,97 @@
|
|||
A {
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A:active {
|
||||
color: #003399;
|
||||
}
|
||||
|
||||
A:visited {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
TD, TH, SPAN {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
BLOCKQUOTE {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
|
||||
H1, H2, H3, H4, H5, H6 {
|
||||
color: #000000;
|
||||
font-weight:500;
|
||||
margin-top:10px;
|
||||
padding-top:15px;
|
||||
}
|
||||
|
||||
TABLE {
|
||||
border-collapse: collapse;
|
||||
border-spacing:0;
|
||||
border: 1px thin black;
|
||||
empty-cells: hide;
|
||||
}
|
||||
|
||||
TD {
|
||||
padding: 4pt;
|
||||
}
|
||||
|
||||
H1 { font-size: 150%; }
|
||||
H2 { font-size: 140%; }
|
||||
H3 { font-size: 110%; font-weight: bold; }
|
||||
H4 { font-size: 110%; font-weight: bold;}
|
||||
H5 { font-size: 100%; font-style: italic; }
|
||||
H6 { font-size: 100%; font-style: italic; }
|
||||
|
||||
TT {
|
||||
font-size: 90%;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
PRE {
|
||||
font-size: 100%;
|
||||
padding: 5px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #CCCCCC;
|
||||
background-color: #F4F4F4;
|
||||
}
|
||||
|
||||
UL, OL, LI {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
HR {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #CCCCCC;
|
||||
border-width: 0px;
|
||||
padding: 0px;
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.variablelist {
|
||||
padding-top: 10;
|
||||
padding-bottom:10;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.itemizedlist, UL {
|
||||
padding-top: 0;
|
||||
padding-bottom:0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.term {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL HTML configuration file for the Hibernate
|
||||
Reference Documentation.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/html/docbook.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<xsl:param name="graphicsize.extension">0</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- Don't use graphics, use a simple number style -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="Shift_JIS"?>
|
||||
|
||||
<!--
|
||||
|
||||
This is the XSL HTML configuration file for the Hibernate
|
||||
Reference Documentation.
|
||||
|
||||
It took me days to figure out this stuff and fix most of
|
||||
the obvious bugs in the DocBook XSL distribution. Some of
|
||||
the workarounds might not be appropriate with a newer version
|
||||
of DocBook XSL. This file is released as part of Hibernate,
|
||||
hence LGPL licensed.
|
||||
|
||||
christian@hibernate.org
|
||||
-->
|
||||
|
||||
<!DOCTYPE xsl:stylesheet [
|
||||
<!ENTITY db_xsl_path "../../support/docbook-xsl/">
|
||||
]>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
version="1.0"
|
||||
xmlns="http://www.w3.org/TR/xhtml1/transitional"
|
||||
exclude-result-prefixes="#default">
|
||||
|
||||
<xsl:import href="&db_xsl_path;/html/chunk.xsl"/>
|
||||
|
||||
<!--###################################################
|
||||
HTML Settings
|
||||
################################################### -->
|
||||
|
||||
<xsl:param name="chunk.section.depth">'5'</xsl:param>
|
||||
<xsl:param name="use.id.as.filename">'1'</xsl:param>
|
||||
<xsl:param name="html.stylesheet">../shared/css/html.css</xsl:param>
|
||||
|
||||
<!-- These extensions are required for table printing and other stuff -->
|
||||
<xsl:param name="use.extensions">1</xsl:param>
|
||||
<xsl:param name="tablecolumns.extension">0</xsl:param>
|
||||
<xsl:param name="callout.extensions">1</xsl:param>
|
||||
<xsl:param name="graphicsize.extension">0</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Table Of Contents
|
||||
################################################### -->
|
||||
|
||||
<!-- Generate the TOCs for named components only -->
|
||||
<xsl:param name="generate.toc">
|
||||
book toc
|
||||
</xsl:param>
|
||||
|
||||
<!-- Show only Sections up to level 3 in the TOCs -->
|
||||
<xsl:param name="toc.section.depth">3</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Labels
|
||||
################################################### -->
|
||||
|
||||
<!-- Label Chapters and Sections (numbering) -->
|
||||
<xsl:param name="chapter.autolabel">1</xsl:param>
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
<xsl:param name="section.label.includes.component.label" select="1"/>
|
||||
|
||||
<!--###################################################
|
||||
Callouts
|
||||
################################################### -->
|
||||
|
||||
<!-- Don't use graphics, use a simple number style -->
|
||||
<xsl:param name="callout.graphics">0</xsl:param>
|
||||
|
||||
<!-- Place callout marks at this column in annotated areas -->
|
||||
<xsl:param name="callout.defaultcolumn">90</xsl:param>
|
||||
|
||||
<!--###################################################
|
||||
Misc
|
||||
################################################### -->
|
||||
|
||||
<!-- Placement of titles -->
|
||||
<xsl:param name="formal.title.placement">
|
||||
figure after
|
||||
example before
|
||||
equation before
|
||||
table before
|
||||
procedure before
|
||||
</xsl:param>
|
||||
|
||||
</xsl:stylesheet>
|