Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #1968 Multiple ResultMap useAautoMappingCache issue #1987

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ public ResultMap addResultMap(
String extend,
Discriminator discriminator,
List<ResultMapping> resultMappings,
Boolean autoMapping) {
Boolean autoMapping,
boolean useAutoMappingCache) {
id = applyCurrentNamespace(id, false);
extend = applyCurrentNamespace(extend, true);

Expand All @@ -203,7 +204,7 @@ public ResultMap addResultMap(
}
resultMappings.addAll(extendedResultMappings);
}
ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping)
ResultMap resultMap = new ResultMap.Builder(configuration, id, type, resultMappings, autoMapping, useAutoMappingCache)
.discriminator(discriminator)
.build();
configuration.addResultMap(resultMap);
Expand Down Expand Up @@ -402,7 +403,7 @@ private List<ResultMap> getStatementResultMaps(
statementId + "-Inline",
resultType,
new ArrayList<>(),
null).build();
null, ResultMap.DEFAULT_USE_AUTO_MAPPING_CACHE).build();
resultMaps.add(inlineResultMap);
}
return resultMaps;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,24 @@ public class ResultMapResolver {
private final Discriminator discriminator;
private final List<ResultMapping> resultMappings;
private final Boolean autoMapping;
private final boolean useAutoMappingCache;

public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class<?> type, String extend, Discriminator discriminator, List<ResultMapping> resultMappings, Boolean autoMapping) {
public ResultMapResolver(MapperBuilderAssistant assistant, String id, Class<?> type, String extend,
Discriminator discriminator, List<ResultMapping> resultMappings,
Boolean autoMapping, boolean useAutoMappingCache) {
this.assistant = assistant;
this.id = id;
this.type = type;
this.extend = extend;
this.discriminator = discriminator;
this.resultMappings = resultMappings;
this.autoMapping = autoMapping;
this.useAutoMappingCache = useAutoMappingCache;
}

public ResultMap resolve() {
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings, this.autoMapping);
return assistant.addResultMap(this.id, this.type, this.extend, this.discriminator, this.resultMappings,
this.autoMapping, this.useAutoMappingCache);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.UnknownTypeHandler;

import static org.apache.ibatis.mapping.ResultMap.DEFAULT_USE_AUTO_MAPPING_CACHE;

/**
* @author Clinton Begin
* @author Kazuki Shimizu
Expand Down Expand Up @@ -255,7 +257,7 @@ private void applyResultMap(String resultMapId, Class<?> returnType, Arg[] args,
applyResults(results, returnType, resultMappings);
Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator);
// TODO add AutoMappingBehaviour
assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);
assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null, DEFAULT_USE_AUTO_MAPPING_CACHE);
createDiscriminatorResultMaps(resultMapId, returnType, discriminator);
}

Expand All @@ -268,7 +270,7 @@ private void createDiscriminatorResultMaps(String resultMapId, Class<?> resultTy
applyConstructorArgs(c.constructArgs(), resultType, resultMappings);
applyResults(c.results(), resultType, resultMappings);
// TODO add AutoMappingBehaviour
assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null);
assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null, DEFAULT_USE_AUTO_MAPPING_CACHE);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,9 @@ private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> addi
resultMapNode.getValueBasedIdentifier());
String extend = resultMapNode.getStringAttribute("extends");
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
Boolean useAutoMappingCache = resultMapNode.getBooleanAttribute("useAutoMappingCache");
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator,
resultMappings, autoMapping, useAutoMappingCache == null ? ResultMap.DEFAULT_USE_AUTO_MAPPING_CACHE : useAutoMappingCache);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ id CDATA #REQUIRED
type CDATA #REQUIRED
extends CDATA #IMPLIED
autoMapping (true|false) #IMPLIED
useAutoMappingCache (true|false) #IMPLIED
>

<!ELEMENT constructor (idArg*,arg*)>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="useAutoMappingCache">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="constructor">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,10 @@ private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject

private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
final String mapKey = resultMap.getId() + ":" + columnPrefix;
List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
List<UnMappedColumnAutoMapping> autoMapping = null;
if (resultMap.isUseAutoMappingCache()) {
autoMapping = autoMappingsCache.get(mapKey);
}
if (autoMapping == null) {
autoMapping = new ArrayList<>();
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
Expand Down Expand Up @@ -547,7 +550,9 @@ private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper
.doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
}
}
autoMappingsCache.put(mapKey, autoMapping);
if (resultMap.isUseAutoMappingCache()) {
autoMappingsCache.put(mapKey, autoMapping);
}
}
return autoMapping;
}
Expand Down
11 changes: 9 additions & 2 deletions src/main/java/org/apache/ibatis/mapping/ResultMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @author Clinton Begin
*/
public class ResultMap {
public static final boolean DEFAULT_USE_AUTO_MAPPING_CACHE = true;
private Configuration configuration;

private String id;
Expand All @@ -49,6 +50,7 @@ public class ResultMap {
private boolean hasNestedResultMaps;
private boolean hasNestedQueries;
private Boolean autoMapping;
private boolean useAutoMappingCache;

private ResultMap() {
}
Expand All @@ -59,15 +61,17 @@ public static class Builder {
private ResultMap resultMap = new ResultMap();

public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings) {
this(configuration, id, type, resultMappings, null);
this(configuration, id, type, resultMappings, null, DEFAULT_USE_AUTO_MAPPING_CACHE);
}

public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings, Boolean autoMapping) {
public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings,
Boolean autoMapping, boolean useAutoMappingCache) {
resultMap.configuration = configuration;
resultMap.id = id;
resultMap.type = type;
resultMap.resultMappings = resultMappings;
resultMap.autoMapping = autoMapping;
resultMap.useAutoMappingCache = useAutoMappingCache;
}

public Builder discriminator(Discriminator discriminator) {
Expand Down Expand Up @@ -258,4 +262,7 @@ public Boolean getAutoMapping() {
return autoMapping;
}

public boolean isUseAutoMappingCache() {
return useAutoMappingCache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.apache.ibatis.submitted.automappingcache;

public class AnotherEntity {
private Integer id;
private String otherField;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getOtherField() {
return otherField;
}

public void setOtherField(String otherField) {
this.otherField = otherField;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.apache.ibatis.submitted.automappingcache;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.Reader;
import java.sql.Connection;
import java.util.List;

public class AutoMappingCacheTest {

private static SqlSessionFactory sqlSessionFactory;

@BeforeClass
public static void setUp() throws Exception {
// create an SqlSessionFactory
try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/automappingcache/mybatis-config.xml")) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
// prepare in-memory database
try (SqlSession session = sqlSessionFactory.openSession();
Connection conn = session.getConnection();
Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/automappingcache/CreateDB.sql");
Reader spReader = Resources.getResourceAsReader("org/apache/ibatis/submitted/automappingcache/StoreProcedure.sql")) {
ScriptRunner runner = new ScriptRunner(conn);
runner.setLogWriter(null);
runner.runScript(reader);

ScriptRunner spRunner = new ScriptRunner(conn);
spRunner.setLogWriter(null);
spRunner.setSendFullScript(true);
spRunner.runScript(spReader);
}
}

@Test
@SuppressWarnings("unchecked")
public void shouldGetMultipleResult() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Mapper mapper = sqlSession.getMapper(Mapper.class);
List<List<?>> results = mapper.getMultipleResultSet();
List<AnotherEntity> anotherEntities = (List<AnotherEntity>) results.get(0);
List<User> userWithInner = (List<User>) results.get(1);
List<User> userWithoutInner = (List<User>) results.get(2);

Assert.assertEquals(2, anotherEntities.size());
Assert.assertEquals(4, userWithInner.size());
Assert.assertEquals(2, userWithoutInner.size());
userWithInner.forEach(user -> {
Assert.assertNotNull(user.getInnerEntity());
Assert.assertNotNull(user.getInnerEntity().getComplexCalculated());
});
userWithoutInner.forEach(user -> {
Assert.assertNull(user.getInnerEntity());
});
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
drop table users if exists;
drop table inner_entity if exists ;
drop table another_entity if exists ;
create table users (
id int,
name varchar(20)
);

create table inner_entity
(
id int,
user_id int,
complexCalculated int
);

create table another_entity
(
id int,
otherField varchar(20)
);

insert into users (id, name) values
(1, 'PatternOne'),
(2, 'PatternOne'),
(3, 'PatternTwo'),
(4, 'PatternTwo');

insert into inner_entity (id, user_id, complexCalculated) values
(1, 1, 111),
(2, 1, 1111),
(3, 2, 222),
(4, 2, 2222);

insert into another_entity (id, otherField) values
(1, 'EntityOne'),
(2, 'EntityTwo');
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.apache.ibatis.submitted.automappingcache;

public class InnerEntity {
private Integer id;
private Integer complexCalculated;
private User user;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public Integer getComplexCalculated() {
return complexCalculated;
}

public void setComplexCalculated(Integer complexCalculated) {
this.complexCalculated = complexCalculated;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.apache.ibatis.submitted.automappingcache;

import java.util.List;

public interface Mapper {
List<List<?>> getMultipleResultSet();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.automappingcache.Mapper">

<resultMap id="anotherEntityMap" type="org.apache.ibatis.submitted.automappingcache.AnotherEntity">
<id column="id" />
<result property="otherField" column="otherField" />
</resultMap>
<!--We need autoMapping, but can't use association in our real use case-->
<resultMap id="multiResultSetMap" type="org.apache.ibatis.submitted.automappingcache.User" autoMapping="true" useAutoMappingCache="false">
<id column="id" />
<result property="name" column="name" />
</resultMap>
<select id="getMultipleResultSet" resultMap="anotherEntityMap,multiResultSetMap,multiResultSetMap">
{call get_multi_resultSets()}
</select>

</mapper>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CREATE PROCEDURE get_multi_resultSets()
READS SQL DATA DYNAMIC RESULT SETS 3
BEGIN ATOMIC
DECLARE result1 CURSOR WITH RETURN FOR
SELECT id, otherField FROM another_entity FOR READ ONLY;

DECLARE result2 CURSOR WITH RETURN FOR
SELECT u.id,name,
ie.id as "innerEntity.id",
ie.user_id as "innerEntity.user.id",
ie.complexCalculated AS "innerEntity.complexCalculated"
FROM users u inner join inner_entity ie on u.id = ie.user_id
WHERE name='PatternOne' FOR READ ONLY;

DECLARE result3 CURSOR WITH RETURN FOR
SELECT * FROM users
WHERE name = 'PatternTwo' FOR READ ONLY;

OPEN result1; OPEN result2; OPEN result3;
END;
Loading