Skip to content

Commit 1562473

Browse files
committed
Edited en doc a little bit and copied the doc changes to the other locales
Copying new doc is now much harder. I knew this was going to happen... I shouldn't have budged 😣 mybatis#2784 (comment)
1 parent 212cbad commit 1562473

File tree

5 files changed

+473
-4
lines changed

5 files changed

+473
-4
lines changed

src/site/es/xdoc/sqlmap-xml.xml

+117
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,123 @@ public class User {
10381038
</tbody>
10391039
</table>
10401040

1041+
<h5>Nested Results for association or collection</h5>
1042+
1043+
<p>While the following sections describe how to use <code>association</code> and <code>collection</code> for both Nested selects and Nested results, Since 3.6.0 we can now inject both using <code>constructor</code> mapping.</p>
1044+
1045+
<p>Considering the following:</p>
1046+
1047+
<source><![CDATA[public class User {
1048+
//...
1049+
public User(Integer id, String username, List<UserRole> userRoles) {
1050+
//...
1051+
}
1052+
}
1053+
1054+
public class UserRole {
1055+
// ...
1056+
public UserRole(Integer id, String role) {
1057+
// ...
1058+
}
1059+
}
1060+
]]></source>
1061+
1062+
<p>We can map <code>UserRole</code> as a nested result, MyBatis will wait until the row has been fully &#x2018;completed&#x2019; before creating the object, this means that by the time the <code>User</code> gets created, <code>userRoles</code> will be complete and cannot be modified anymore.</p>
1063+
1064+
<source><![CDATA[<resultMap id="userResultMap" type="User">
1065+
<constructor>
1066+
<idArg column="id" javaType="int" />
1067+
<arg column="username" javaType="String" />
1068+
<arg javaType="List" resultMap="userRoleResultMap" columnPrefix="role_"/>
1069+
</constructor>
1070+
</resultMap>
1071+
]]></source>
1072+
1073+
<p>To achieve fully immutable objects in this example, we can also use constructor injection for <code>UserRole</code></p>
1074+
1075+
<source><![CDATA[<resultMap id="userRoleResultMap" type="UserRole">
1076+
<constructor>
1077+
<idArg column="id" javaType="int" />
1078+
<arg column="role" javaType="String" />
1079+
</constructor>
1080+
</resultMap>
1081+
]]></source>
1082+
1083+
<p>MyBatis needs to be explicitly told that the results have been ordered in such a way, that when a new main row is retrieved from the result set, no previous row results will be retrieved again. This can be set on the statement with the <code>resultOrdered</code> attribute:</p>
1084+
1085+
<source><![CDATA[<select id="getAllUsers" resultMap="userResultMap" resultOrdered="true">
1086+
select
1087+
u.id,
1088+
u.username,
1089+
r.id as role_id,
1090+
r.role as role_role,
1091+
from user u
1092+
left join user_role ur on u.id = ur.user_id
1093+
inner join role r on r.id = ur.role_id
1094+
order by u.id, r.id
1095+
</select>
1096+
]]></source>
1097+
1098+
<p>Note that <code>order by</code> is specified to order the results correctly. We can imagine the output to look something like:</p>
1099+
1100+
<table class="table table-striped">
1101+
<thead>
1102+
<tr class="a">
1103+
<th>row_nr</th>
1104+
<th>u.id</th>
1105+
<th>u.username</th>
1106+
<th>r.id</th>
1107+
<th>r.role</th></tr></thead><tbody>
1108+
<tr class="b">
1109+
<td>1</td>
1110+
<td>1</td>
1111+
<td>John</td>
1112+
<td>1</td>
1113+
<td>Admins</td></tr>
1114+
<tr class="a">
1115+
<td>2</td>
1116+
<td>1</td>
1117+
<td>John</td>
1118+
<td>2</td>
1119+
<td>Users</td></tr>
1120+
<tr class="b">
1121+
<td>3</td>
1122+
<td>2</td>
1123+
<td>Jack</td>
1124+
<td>null</td>
1125+
<td>null</td></tr>
1126+
<tr class="a">
1127+
<td>4</td>
1128+
<td>3</td>
1129+
<td>Peter</td>
1130+
<td>2</td>
1131+
<td>Users</td></tr>
1132+
<tr class="b">
1133+
<td>5</td>
1134+
<td>3</td>
1135+
<td>Peter</td>
1136+
<td>3</td>
1137+
<td>Maintainers</td></tr>
1138+
<tr class="a">
1139+
<td>6</td>
1140+
<td>3</td>
1141+
<td>Peter</td>
1142+
<td>4</td>
1143+
<td>Approvers</td></tr></tbody>
1144+
</table>
1145+
1146+
<p>After this query is run, we would have the following results:</p>
1147+
1148+
<source><![CDATA[User{username=John, roles=[Admins, Users]}
1149+
User{username=Jack, roles=[]}
1150+
User{username=Peter, roles=[Users, Maintainers, Approvers]}
1151+
]]></source>
1152+
1153+
<p>If the 5th row here would have somehow appeared below the first row (via some <code>ORDER BY</code>), MyBatis would not be able to fully construct the <code>John</code> user correctly using constructor collection mapping.</p>
1154+
1155+
<p>It is important to note that mixed mappings have limited support, i.e. property mappings combined with nested constructor mappings are likely to fail.
1156+
When using this functionality, it is preferable for the entire mapping hierarchy to use immutable constructor mappings.</p>
1157+
10411158
<h4>association</h4>
10421159

10431160
<source><![CDATA[<association property="author" javaType="Author">

src/site/ja/xdoc/sqlmap-xml.xml

+117
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,123 @@ public class User {
11761176
</tbody>
11771177
</table>
11781178

1179+
<h5>コレクションや複雑なオブジェクトを引数に含むコンストラクタに対して、ネストされた結果をマッピングする</h5>
1180+
1181+
<p>以降のセクションで <code>association</code> と <code>collection</code> について説明しますが、バージョン 3.6.0 以降ではコンストラクタの引数としてコレクションを指定できるようになりました。</p>
1182+
1183+
<p>次のクラスを例にして説明します。</p>
1184+
1185+
<source><![CDATA[public class User {
1186+
//...
1187+
public User(Integer id, String username, List<UserRole> userRoles) {
1188+
//...
1189+
}
1190+
}
1191+
1192+
public class UserRole {
1193+
// ...
1194+
public UserRole(Integer id, String role) {
1195+
// ...
1196+
}
1197+
}
1198+
]]></source>
1199+
1200+
<p>クエリがネストされた結果を返す場合、<code>User</code> のコンストラクタ引数に含まれているコレクション <code>List&lt;UserRole&gt;</code> をマッピングするためには、下記のような ResultMap を定義します。</p>
1201+
<p>MyBatis は <code>UserRole</code> が全て読み込まれてから <code>User</code> のコンストラクタを呼び出します。つまり、<code>User</code> をイミュータブルなオブジェクトとして定義することもできるということです。</p>
1202+
1203+
<source><![CDATA[<resultMap id="userResultMap" type="User">
1204+
<constructor>
1205+
<idArg column="id" javaType="int" />
1206+
<arg column="username" javaType="String" />
1207+
<arg javaType="List" resultMap="userRoleResultMap" columnPrefix="role_"/>
1208+
</constructor>
1209+
</resultMap>
1210+
]]></source>
1211+
1212+
<p>上記の ResultMap で参照している <code>UserRole</code> 用の ResultMap でもコンストラクタマッピングを使用すれば、<code>UserRole</code> もイミュータブルにできます。</p>
1213+
1214+
<source><![CDATA[<resultMap id="userRoleResultMap" type="UserRole">
1215+
<constructor>
1216+
<idArg column="id" javaType="int" />
1217+
<arg column="role" javaType="String" />
1218+
</constructor>
1219+
</resultMap>
1220+
]]></source>
1221+
1222+
<p>このマッピングを実現するためには、結果セットが正しい順番でソートされていることが前提となるので、クエリで適切な <code>ORDER BY</code> 句を指定した上で、<code>&lt;select&gt;</code> 要素の <code>resultOrdered</code> 属性に <code>true</code> を設定してください。</p>
1223+
1224+
<source><![CDATA[<select id="getAllUsers" resultMap="userResultMap" resultOrdered="true">
1225+
select
1226+
u.id,
1227+
u.username,
1228+
r.id as role_id,
1229+
r.role as role_role,
1230+
from user u
1231+
left join user_role ur on u.id = ur.user_id
1232+
inner join role r on r.id = ur.role_id
1233+
order by u.id, r.id
1234+
</select>
1235+
]]></source>
1236+
1237+
<p>下記のように正しくソートされた結果セットが返ってくれば、期待通りにマッピングすることができます。</p>
1238+
1239+
<table class="table table-striped">
1240+
<thead>
1241+
<tr class="a">
1242+
<th>row_nr</th>
1243+
<th>u.id</th>
1244+
<th>u.username</th>
1245+
<th>r.id</th>
1246+
<th>r.role</th></tr></thead><tbody>
1247+
<tr class="b">
1248+
<td>1</td>
1249+
<td>1</td>
1250+
<td>John</td>
1251+
<td>1</td>
1252+
<td>Admins</td></tr>
1253+
<tr class="a">
1254+
<td>2</td>
1255+
<td>1</td>
1256+
<td>John</td>
1257+
<td>2</td>
1258+
<td>Users</td></tr>
1259+
<tr class="b">
1260+
<td>3</td>
1261+
<td>2</td>
1262+
<td>Jack</td>
1263+
<td>null</td>
1264+
<td>null</td></tr>
1265+
<tr class="a">
1266+
<td>4</td>
1267+
<td>3</td>
1268+
<td>Peter</td>
1269+
<td>2</td>
1270+
<td>Users</td></tr>
1271+
<tr class="b">
1272+
<td>5</td>
1273+
<td>3</td>
1274+
<td>Peter</td>
1275+
<td>3</td>
1276+
<td>Maintainers</td></tr>
1277+
<tr class="a">
1278+
<td>6</td>
1279+
<td>3</td>
1280+
<td>Peter</td>
1281+
<td>4</td>
1282+
<td>Approvers</td></tr></tbody>
1283+
</table>
1284+
1285+
<p>作成される <code>User</code> オブジェクトは下記のようになります。</p>
1286+
1287+
<source><![CDATA[User{username=John, roles=[Admins, Users]}
1288+
User{username=Jack, roles=[]}
1289+
User{username=Peter, roles=[Users, Maintainers, Approvers]}
1290+
]]></source>
1291+
1292+
<p>仮に、誤ったソート条件が指定されていて5行目のデータが1行目の直後に出現するようなクエリを実行してしまうと、全ての <code>UserRole</code> を読み込む前に <code>John</code> ユーザのコンストラクタが呼び出されてしまうので、期待通りの結果を得ることはできません。</p>
1293+
1294+
<p>コンストラクタ引数にコレクションを含むオブジェクトを使う場合は、完全にイミュータブルなオブジェクトとして定義してください。ResultMap にコンストラクタマッピングとプロパティマッピングが混在する ResultMap は正しく動作しない可能性があります。</p>
1295+
11791296
<h4>association</h4>
11801297

11811298
<source><![CDATA[<association property="author" column="blog_author_id" javaType="Author">

src/site/ko/xdoc/sqlmap-xml.xml

+118
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,124 @@ public class User {
10471047
</tbody>
10481048
</table>
10491049

1050+
<h5>Nested Results for association or collection</h5>
1051+
1052+
<p>While the following sections describe how to use <code>association</code> and <code>collection</code> for both Nested selects and Nested results, Since 3.6.0 we can now inject both using <code>constructor</code> mapping.</p>
1053+
1054+
<p>Considering the following:</p>
1055+
1056+
<source><![CDATA[public class User {
1057+
//...
1058+
public User(Integer id, String username, List<UserRole> userRoles) {
1059+
//...
1060+
}
1061+
}
1062+
1063+
public class UserRole {
1064+
// ...
1065+
public UserRole(Integer id, String role) {
1066+
// ...
1067+
}
1068+
}
1069+
]]></source>
1070+
1071+
<p>We can map <code>UserRole</code> as a nested result, MyBatis will wait until the row has been fully &#x2018;completed&#x2019; before creating the object, this means that by the time the <code>User</code> gets created, <code>userRoles</code> will be complete and cannot be modified anymore.</p>
1072+
1073+
<source><![CDATA[<resultMap id="userResultMap" type="User">
1074+
<constructor>
1075+
<idArg column="id" javaType="int" />
1076+
<arg column="username" javaType="String" />
1077+
<arg javaType="List" resultMap="userRoleResultMap" columnPrefix="role_"/>
1078+
</constructor>
1079+
</resultMap>
1080+
]]></source>
1081+
1082+
<p>To achieve fully immutable objects in this example, we can also use constructor injection for <code>UserRole</code></p>
1083+
1084+
<source><![CDATA[<resultMap id="userRoleResultMap" type="UserRole">
1085+
<constructor>
1086+
<idArg column="id" javaType="int" />
1087+
<arg column="role" javaType="String" />
1088+
</constructor>
1089+
</resultMap>
1090+
]]></source>
1091+
1092+
<p>MyBatis needs to be explicitly told that the results have been ordered in such a way, that when a new main row is retrieved from the result set, no previous row results will be retrieved again. This can be set on the statement with the <code>resultOrdered</code> attribute:</p>
1093+
1094+
<source><![CDATA[<select id="getAllUsers" resultMap="userResultMap" resultOrdered="true">
1095+
select
1096+
u.id,
1097+
u.username,
1098+
r.id as role_id,
1099+
r.role as role_role,
1100+
from user u
1101+
left join user_role ur on u.id = ur.user_id
1102+
inner join role r on r.id = ur.role_id
1103+
order by u.id, r.id
1104+
</select>
1105+
]]></source>
1106+
1107+
<p>Note that <code>order by</code> is specified to order the results correctly. We can imagine the output to look something like:</p>
1108+
1109+
<table class="table table-striped">
1110+
<thead>
1111+
<tr class="a">
1112+
<th>row_nr</th>
1113+
<th>u.id</th>
1114+
<th>u.username</th>
1115+
<th>r.id</th>
1116+
<th>r.role</th></tr></thead><tbody>
1117+
<tr class="b">
1118+
<td>1</td>
1119+
<td>1</td>
1120+
<td>John</td>
1121+
<td>1</td>
1122+
<td>Admins</td></tr>
1123+
<tr class="a">
1124+
<td>2</td>
1125+
<td>1</td>
1126+
<td>John</td>
1127+
<td>2</td>
1128+
<td>Users</td></tr>
1129+
<tr class="b">
1130+
<td>3</td>
1131+
<td>2</td>
1132+
<td>Jack</td>
1133+
<td>null</td>
1134+
<td>null</td></tr>
1135+
<tr class="a">
1136+
<td>4</td>
1137+
<td>3</td>
1138+
<td>Peter</td>
1139+
<td>2</td>
1140+
<td>Users</td></tr>
1141+
<tr class="b">
1142+
<td>5</td>
1143+
<td>3</td>
1144+
<td>Peter</td>
1145+
<td>3</td>
1146+
<td>Maintainers</td></tr>
1147+
<tr class="a">
1148+
<td>6</td>
1149+
<td>3</td>
1150+
<td>Peter</td>
1151+
<td>4</td>
1152+
<td>Approvers</td></tr></tbody>
1153+
</table>
1154+
1155+
<p>After this query is run, we would have the following results:</p>
1156+
1157+
<source><![CDATA[User{username=John, roles=[Admins, Users]}
1158+
User{username=Jack, roles=[]}
1159+
User{username=Peter, roles=[Users, Maintainers, Approvers]}
1160+
]]></source>
1161+
1162+
<p>If the 5th row here would have somehow appeared below the first row (via some <code>ORDER BY</code>), MyBatis would not be able to fully construct the <code>John</code> user correctly using constructor collection mapping.</p>
1163+
1164+
<p>It is important to note that mixed mappings have limited support, i.e. property mappings combined with nested constructor mappings are likely to fail.
1165+
When using this functionality, it is preferable for the entire mapping hierarchy to use immutable constructor mappings.</p>
1166+
1167+
10501168
<h4>association</h4>
10511169

10521170
<source><![CDATA[<association property="author" column="blog_author_id" javaType="Author">

0 commit comments

Comments
 (0)