Skip to content

Commit 7a6e401

Browse files
committed
Merge of fix for #255 into 3.2.x branch
1 parent d79a043 commit 7a6e401

File tree

10 files changed

+422
-13
lines changed

10 files changed

+422
-13
lines changed

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public class DefaultResultSetHandler implements ResultSetHandler {
7878

7979
// multiple resultsets
8080
private final Map<String, ResultMapping> nextResultMaps = new HashMap<String, ResultMapping>();
81-
private final Map<CacheKey, PendingRelation> pendingRelations = new HashMap<CacheKey, PendingRelation>();
81+
private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<CacheKey, List<PendingRelation>>();
8282

8383
private static class PendingRelation {
8484
public MetaObject metaObject;
@@ -295,7 +295,7 @@ private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap r
295295

296296
private void storeObject(ResultHandler resultHandler, DefaultResultContext resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
297297
if (parentMapping != null) {
298-
linkToParent(rs, parentMapping, rowValue);
298+
linkToParents(rs, parentMapping, rowValue);
299299
} else {
300300
callResultHandler(resultHandler, resultContext, rowValue);
301301
}
@@ -425,17 +425,19 @@ private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap
425425

426426
// MULTIPLE RESULT SETS
427427

428-
private void linkToParent(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
428+
private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
429429
CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(), parentMapping.getForeignColumn());
430-
PendingRelation parent = pendingRelations.get(parentKey);
431-
if (parent != null) {
432-
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(parent.propertyMapping, parent.metaObject);
433-
if (rowValue != null) {
434-
if (collectionProperty != null) {
435-
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
436-
targetMetaObject.add(rowValue);
437-
} else {
438-
parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
430+
List<PendingRelation> parents = pendingRelations.get(parentKey);
431+
for (PendingRelation parent : parents) {
432+
if (parent != null) {
433+
final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(parent.propertyMapping, parent.metaObject);
434+
if (rowValue != null) {
435+
if (collectionProperty != null) {
436+
final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
437+
targetMetaObject.add(rowValue);
438+
} else {
439+
parent.metaObject.setValue(parent.propertyMapping.getProperty(), rowValue);
440+
}
439441
}
440442
}
441443
}
@@ -469,7 +471,13 @@ private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject,
469471
PendingRelation deferLoad = new PendingRelation();
470472
deferLoad.metaObject = metaResultObject;
471473
deferLoad.propertyMapping = parentMapping;
472-
pendingRelations.put(cacheKey, deferLoad);
474+
List<PendingRelation> relations = pendingRelations.get(cacheKey);
475+
// issue #255
476+
if (relations == null) {
477+
relations = new ArrayList<DefaultResultSetHandler.PendingRelation>();
478+
pendingRelations.put(cacheKey, relations);
479+
}
480+
relations.add(deferLoad);
473481
ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
474482
if (previous == null) {
475483
nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
-- Copyright 2009-2012 the original author or authors.
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
DROP PROCEDURE GetOrderDetailsAndHeaders IF EXISTS;
16+
DROP TABLE order_detail IF EXISTS;
17+
DROP TABLE order_header IF EXISTS;
18+
19+
CREATE TABLE order_detail
20+
(
21+
order_id integer NOT NULL,
22+
line_number integer NOT NULL,
23+
quantity integer NOT NULL,
24+
item_description varchar(50) NOT NULL,
25+
PRIMARY KEY (order_id, line_number)
26+
);
27+
28+
CREATE TABLE order_header
29+
(
30+
order_id integer NOT NULL,
31+
cust_name varchar(50) NOT NULL,
32+
PRIMARY KEY (order_id)
33+
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- Copyright 2009-2012 the original author or authors.
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
CREATE PROCEDURE GetOrderDetailsAndHeaders()
16+
READS SQL DATA
17+
DYNAMIC RESULT SETS 1
18+
BEGIN ATOMIC
19+
20+
DECLARE result1 CURSOR FOR
21+
SELECT * FROM order_detail
22+
FOR READ ONLY ;
23+
24+
DECLARE result2 CURSOR FOR
25+
SELECT * FROM order_header
26+
FOR READ ONLY ;
27+
28+
OPEN result1 ;
29+
OPEN result2 ;
30+
END;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- Copyright 2009-2012 the original author or authors.
2+
--
3+
-- Licensed under the Apache License, Version 2.0 (the "License");
4+
-- you may not use this file except in compliance with the License.
5+
-- You may obtain a copy of the License at
6+
--
7+
-- http://www.apache.org/licenses/LICENSE-2.0
8+
--
9+
-- Unless required by applicable law or agreed to in writing, software
10+
-- distributed under the License is distributed on an "AS IS" BASIS,
11+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
-- See the License for the specific language governing permissions and
13+
-- limitations under the License.
14+
15+
INSERT INTO order_header(order_id, cust_name)
16+
VALUES (1, 'Fred');
17+
INSERT INTO order_header(order_id, cust_name)
18+
VALUES (2, 'Barney');
19+
20+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
21+
VALUES (1, 1, 1, 'Pen');
22+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
23+
VALUES (1, 2, 3, 'Pencil');
24+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
25+
VALUES (1, 3, 2, 'Notepad');
26+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
27+
VALUES (2, 1, 1, 'Compass');
28+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
29+
VALUES (2, 2, 1, 'Protractor');
30+
INSERT INTO order_detail(order_id, line_number, quantity, item_description)
31+
VALUES (2, 3, 2, 'Pencil');
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2009-2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.submitted.multipleresultsetswithassociation;
17+
18+
import java.util.List;
19+
20+
public interface Mapper {
21+
22+
List<OrderDetail> getOrderDetailsWithHeaders();
23+
24+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2009-2012 the original author or authors.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<!DOCTYPE mapper
18+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
19+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
20+
21+
<mapper namespace="org.apache.ibatis.submitted.multipleresultsetswithassociation.Mapper">
22+
23+
<select id="getOrderDetailsWithHeaders" resultSets="orderDetailResultSet,orderHeaderResultSet" resultMap="orderDetailResultMap" statementType="CALLABLE">
24+
{ call GetOrderDetailsAndHeaders() }
25+
</select>
26+
27+
<resultMap type="org.apache.ibatis.submitted.multipleresultsetswithassociation.OrderDetail" id="orderDetailResultMap">
28+
<id property="orderId" column="order_id"/>
29+
<id property="lineNumber" column="line_number"/>
30+
<association property="orderHeader" column="order_id" foreignColumn="order_id"
31+
resultSet="orderHeaderResultSet" resultMap="orderHeaderResultMap" />
32+
</resultMap>
33+
34+
<resultMap type="org.apache.ibatis.submitted.multipleresultsetswithassociation.OrderHeader" id="orderHeaderResultMap">
35+
<id property="orderId" column="order_id"/>
36+
</resultMap>
37+
38+
</mapper>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2009-2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.submitted.multipleresultsetswithassociation;
17+
18+
import java.io.IOException;
19+
import java.io.Reader;
20+
import java.sql.Connection;
21+
import java.util.List;
22+
23+
import org.apache.ibatis.io.Resources;
24+
import org.apache.ibatis.jdbc.ScriptRunner;
25+
import org.apache.ibatis.session.SqlSession;
26+
import org.apache.ibatis.session.SqlSessionFactory;
27+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
28+
import org.junit.Assert;
29+
import org.junit.BeforeClass;
30+
import org.junit.Test;
31+
32+
/*
33+
* This class contains tests for multiple result sets with an association mapping.
34+
* This test is based on the org.apache.ibatis.submitted.multiple_resultsets test.
35+
*
36+
*/
37+
public class MultipleResultSetTest {
38+
39+
private static SqlSessionFactory sqlSessionFactory;
40+
41+
@BeforeClass
42+
public static void setUp() throws Exception {
43+
Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multipleresultsetswithassociation/mybatis-config.xml");
44+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
45+
reader.close();
46+
47+
// populate in-memory database
48+
// Could not get the table creation, procedure creation, and data population to work from the same script.
49+
// Once it was in three scripts, all seemed well.
50+
SqlSession session = sqlSessionFactory.openSession();
51+
Connection conn = session.getConnection();
52+
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multipleresultsetswithassociation/CreateDB1.sql");
53+
runReaderScript(conn, session, reader);
54+
reader.close();
55+
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multipleresultsetswithassociation/CreateDB2.sql");
56+
runReaderScript(conn, session, reader);
57+
reader.close();
58+
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/multipleresultsetswithassociation/CreateDB3.sql");
59+
runReaderScript(conn, session, reader);
60+
reader.close();
61+
session.close();
62+
}
63+
64+
private static void runReaderScript(Connection conn, SqlSession session, Reader reader) throws Exception {
65+
ScriptRunner runner = new ScriptRunner(conn);
66+
runner.setLogWriter(null);
67+
runner.setSendFullScript(true);
68+
runner.setAutoCommit(true);
69+
runner.setStopOnError(false);
70+
runner.runScript(reader);
71+
}
72+
73+
@Test
74+
public void shouldGetOrderDetailsEachHavingAnOrderHeader() throws IOException {
75+
SqlSession sqlSession = sqlSessionFactory.openSession();
76+
try {
77+
Mapper mapper = sqlSession.getMapper(Mapper.class);
78+
List<OrderDetail> orderDetails = mapper.getOrderDetailsWithHeaders();
79+
80+
// There are six order detail records in the database
81+
// As long as the data does not change this should be successful
82+
Assert.assertEquals(6, orderDetails.size());
83+
84+
// Each order detail should have a corresponding OrderHeader
85+
// Only 2 of 6 orderDetails have orderHeaders
86+
for(OrderDetail orderDetail : orderDetails){
87+
Assert.assertNotNull(orderDetail.getOrderHeader());
88+
}
89+
90+
} finally {
91+
sqlSession.close();
92+
}
93+
}
94+
95+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2009-2012 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.submitted.multipleresultsetswithassociation;
17+
18+
public class OrderDetail {
19+
20+
private int orderId;
21+
private int lineNumber;
22+
private int quantity;
23+
private String itemDescription;
24+
25+
private OrderHeader orderHeader;
26+
27+
public int getOrderId() {
28+
return orderId;
29+
}
30+
31+
public void setOrderId(int orderId) {
32+
this.orderId = orderId;
33+
}
34+
35+
public int getLineNumber() {
36+
return lineNumber;
37+
}
38+
39+
public void setLineNumber(int lineNumber) {
40+
this.lineNumber = lineNumber;
41+
}
42+
43+
public int getQuantity() {
44+
return quantity;
45+
}
46+
47+
public void setQuantity(int quantity) {
48+
this.quantity = quantity;
49+
}
50+
51+
public String getItemDescription() {
52+
return itemDescription;
53+
}
54+
55+
public void setItemDescription(String itemDescription) {
56+
this.itemDescription = itemDescription;
57+
}
58+
59+
public OrderHeader getOrderHeader() {
60+
return orderHeader;
61+
}
62+
63+
public void setOrderHeader(OrderHeader orderHeader) {
64+
this.orderHeader = orderHeader;
65+
}
66+
}

0 commit comments

Comments
 (0)