Reputation: 43
I'm working on a springboot app in which mybatis is calling a DB2 stored procedure and this stored procedure is returning 2 result sets: and for each result set I defined a model(Fruit.java and Animal.java)
result set #1
ID | NAME | QTY |
---|---|---|
1 | Apple | 2 |
2 | Orange | 3 |
3 | banana | 5 |
result set #2
TYPE | NUM | LOC |
---|---|---|
monkey | 2000 | London |
dog | 3000 | New York |
cat | 8000 | LA |
in MyMapper.java, what should my resultType be?
I have tried:
@Select(Value = "{call ....})
@Options(StatementType = StatementType.CALLABLE)
@Results({
@Result(property="id", column="ID",
@Result(property="name", column="NAME",
@Result(property="qty", column="QTY" })
List<Fruit> getFruits(Map<String, String> params);
@Select(Value = "{call ....})
@Options(StatementType = StatementType.CALLABLE)
@Results({
@Result(property="type", column="TYPE",
@Result(property="num", column="NUM",
@Result(property="loc", column="LOC"
})
List<Animal> getAnimals(Map<String, String> params);
which didn't work, I did get result set #1 ok this way but not getting result set #2 (all fields from result set#2 came back null) .
I also tried:
@Select(Value = "{call ....})
@Options(StatementType = StatementType.CALLABLE)
List<?> getResultSets(Map<String, String> params);
and:
@Select(Value = "{call ....})
@Options(StatementType = StatementType.CALLABLE)
List<List<?>> getResultSets(Map<String, String> params);
For both I got "java.lang.UnsupportedOperationException":
Caused by: java.lang.UnsupportedOperationException
at org.apache.ibatis.reflection.wrapper.CollectionWrapper.findProperty(CollectionWrapper.java:42)
at org.apache.ibatis.reflection.MetaObject.findProperty(MetaObject.java:76)
at org.apache.ibatis.executor.resultset.FastResultSetHandler.applyAutomaticMappings(FastResultSetHandler.java:342)
at org.apache.ibatis.executor.resultset.FastResultSetHandler.getRowValue(FastResultSetHandler.java:267)
at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleRowValues(FastResultSetHandler.java:216)
at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleResultSet(FastResultSetHandler.java:188)
at org.apache.ibatis.executor.resultset.FastResultSetHandler.handleResultSets(FastResultSetHandler.java:154)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:57)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:70)
at org.apache.ibatis.executor.ReuseExecutor.doQuery(ReuseExecutor.java:54)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:259)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:132)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:105)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:81)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
Google says it's because I should use a concrete type instead of generics. But the result sets are of different types: List of Fruit and List of Animal , what do I do?
I'm using all annotations and no xml for mybatis. in pom.xml I'm using mybatis-spring-boot-starter if that helps.
I have been stuck on this forever. Thanks.
Upvotes: 3
Views: 1150
Reputation: 3594
I tested this with the following procedure.
It takes two IN parameters and returns the results for fruit
first, then animal
.
Let me know if you need me to make some adjustments.
create or replace procedure test_proc (
in p1 varchar(20),
in p2 varchar(20)
)
dynamic result sets 2
begin
declare c1 cursor with return to caller for
select * from animal;
declare c2 cursor with return to caller for
select * from fruit;
open c2;
open c1;
end
The Java mapper method would look as follows.
As you receive two result sets, you need to specify two result maps in @ResultMap
.
Note that the order matters.
@Select("{call test_proc(#{p1,mode=IN,jdbcType=VARCHAR},#{p2,mode=IN,jdbcType=VARCHAR})}")
@Options(statementType = StatementType.CALLABLE)
@ResultMap("fruitResultMap,animalResultMap")
List<List<?>> execProc(Map<String, String> params);
The returned list contains two lists. The first one is List<Fruit>
and the second one is List<Animal>
.
Now, to define those result maps without XML mapper, you need to declare extra methods.
@Results(id = "fruitResultMap", value = {
@Result(property = "id", column = "ID"),
@Result(property = "name", column = "NAME"),
@Result(property = "qty", column = "QTY")
})
@Select("select * from fruit")
List<Fruit> getFruits();
@Results(id = "animalResultMap", value = {
@Result(property = "type", column = "TYPE"),
@Result(property = "num", column = "NUM"),
@Result(property = "loc", column = "LOC")
})
@Select("select * from animal")
List<Animal> getAnimals();
And here is an executable demo project:
https://github.com/harawata/mybatis-issues/tree/master/so-69145531
Upvotes: 2