关注guideline for multiple resultsets并在this answer的帮助下,我现在能够提取2个不同的记录集,但它们只是列表而不是映射到结果对象。
我有课程(简化):
public class SupplyChain{
private String id;
private List<SupplyChainNode> nodes;
private List<SupplyChainEdge> edges;
}
public class SupplyChainNode {
private String id;
private String label;
}
public class SupplyChainEdge {
private String id;
private String label;
}
MyBatis
接口声明如下:
public interface SupplyChainMBDao {
List<SupplyChain> getByPartyId(@Param("partyId") String partyId);
}
MyBatis
映射:
<mapper namespace="ru.rlh.egais.portal.backend.dao.mybatis.SupplyChainMBDao">
<select id="getByPartyId" resultSets="edges,nodes" resultMap="supplyChainMapEdge, supplyChainMapNode"><![CDATA[
-- There big query returns 2 recordset - first for Edges and second for Nodes. They have different amount of rows and logic of obtain, but share initial computation and it is desire to return them atomic.
-- Let it be for simplicity:
SELECT * FROM (VALUES(1, 2)) edges(id, label);
SELECT * FROM (VALUES(2, 3), (4, 5)) nodes(id, label)
]]></select>
<resultMap id="supplyChainMapEdge" type="ru.rlh.egais.portal.api.dto.bo.supplychain.SupplyChainEdge" >
<result property="label" column="label"/>
</resultMap>
<resultMap id="supplyChainMapNode" type="ru.rlh.egais.portal.api.dto.bo.supplychain.SupplyChainNode" >
<result property="label" column="label"/>
</resultMap>
</mapper>
所以,基本上它可以工作,我有2个收藏。但是,而不是声明List<SupplyChain>
返回值,我真的得到List<List>
,其中内部列表在运行时包含2个元素:
List<SupplyChainEdge>
List<SupplyChainNode>
。 如何将此原始集合包装到对象SupplyChain
中?
答案 0 :(得分:2)
另一种方法:使用自定义ResultHandler。 我已调试,直到DefaultResultSetHandler.handleResultSets,并发现提供的自定义结果处理程序用于每个“子”结果集而不是全局查询。 然后,结果列表必须直接在期望的位置构建:在supplyChain对象中。
/* the Custom Result Handler */
public class CustomResultHandler implements ResultHandler {
private SupplyChain supplyChain;
public CustomResultHandler(SupplyChain supplyChain) {
this.supplyChain = supplyChain;
}
@Override
public void handleResult(ResultContext ctx) {
Object o = ctx.getResultObject();
/* access to SupplyChain members is simplified here */
if (o instanceof SupplyChainEdge) {
SupplyChainEdge sc = (SupplyChainEdge) o;
if (ctx.getResultCount() == 1) { /* lazy list instantiation */
this.supplyChain.supplyChainEdge = new ArrayList<SupplyChainEdge>();
}
this.supplyChain.supplyChainEdge.add(sc);
} else if (o instanceof SupplyChainNode) {
SupplyChainNode sc = (SupplyChainNode) o;
if (ctx.getResultCount() == 1) { /* lazy list instantiation */
this.supplyChain.supplyChainNode = new ArrayList<SupplyChainNode>();
}
this.supplyChain.supplyChainNode.add(sc);
}
}
}
/* in mapper interface */
void getByPartyId(@Param("partyId") String partyId, ResultHandler handler);
/* how to call it */
SupplyChain supplyChain = new SupplyChain();
ResultHandler handler = new CustomResultHandler();
mapper.getByPartyId(id, handler);
我希望这符合您的期望。 无论如何,我认为这是问题的答案:将集合包装到对象SupplyChain中。
干杯
答案 1 :(得分:1)
我必须猜测&#34;大查询返回2记录集[...]&#34;实际上是一个存储过程,其主体包含2个SELECT语句(正如{strong> Mybatis doc中多个结果集的关联章节中所建议的那样) 这就是你如何获得2个结果集。
您可能确实尝试构建单个SELECT并使用集合/关联映射列。
或者您可以将目标集合绑定到存储过程OUT参数(此处适用于Oracle):
CREATE PROCEDURE p(partyId IN VARCHAR2, rc1 OUT SYS_REFCURSOR, rc2 OUT SYS_REFCURSOR) AS
BEGIN
OPEN rc1 FOR SELECT [...];
OPEN rc2 FOR SELECT [...];
END;
这是Mapper界面(带注释,你可以将它全部转换为XML):
@Select("{ CALL p(#{partyId}),
#{supplyChain.nodes, mode=OUT, jdbcType=CURSOR, javaType=java.sql.ResultSet, resultMap=supplyChainMapNode},
#{supplyChain.edges, mode=OUT, jdbcType=CURSOR, javaType=java.sql.ResultSet, resultMap=supplyChainMapEdge}
}")
@Options(statementType = StatementType.CALLABLE)
void getByPartyId(@Param("partyId") String partyId, @Param("supplyChain") SupplyChain supplyChain);
resultMaps是您在XML中定义的那些。
所以调用映射器,当程序响应时,将填充SupplyChain bean。
无论如何,我想知道使用SELECT或CURSOR之间的行为差异是什么,特别是关于资源管理/性能,考虑到Java最终可以使用resultSets。 例如,我想为fetchSize选项设置一个自定义值(Oracle默认值为10,对于大型结果集来说非常慢(过多的java&lt; - &gt; DB往返))。但到目前为止,我无法弄清楚这个语句选项是否用于绑定out-params。
干杯。