简体   繁体   English

Mybatis将多个结果集映射到对象内部集合中

[英]Mybatis map multiple resultsets into object inner collections

Brief problem description 简要问题描述

Following guideline for multiple resultsets and with help from this answer I now able to extract 2 different recordsets but they are just list and do not mapped on result object. 遵循多个结果集的指导原则并在此答案的帮助下,我现在能够提取2个不同的记录集,但它们只是列表而不是映射到结果对象。

In details 详情

I have classes (simplified): 我有课程(简化):

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 interface declared like: MyBatis接口声明如下:

public interface SupplyChainMBDao {
    List<SupplyChain> getByPartyId(@Param("partyId") String partyId);
}

And MyBatis mapping: 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>

So, basically it works and I got 2 collections. 所以,基本上它工作,我有2个收藏。 But instead of declared List<SupplyChain> return value I really got List<List> where inner list contain 2 elements in runtime: 但是,而不是声明List<SupplyChain>返回值,我真的得到了List<List> ,其中内部列表在运行时包含2个元素:

  • 0 element is List<SupplyChainEdge> 0元素是List<SupplyChainEdge>
  • and 1st: List<SupplyChainNode> . 和1st: List<SupplyChainNode>

How to I can wrap this raw collections into object SupplyChain ? 如何将这个原始集合包装到对象SupplyChain

Another approach: use custom ResultHandler. 另一种方法:使用自定义ResultHandler。 I've debugged until DefaultResultSetHandler.handleResultSets and figured out that provided custom result handler is used on each "sub" result set and not on the global query. 我已调试,直到DefaultResultSetHandler.handleResultSets,并发现提供的自定义结果处理程序用于每个“子”结果集而不是全局查询。 Then the result lists have to be built directly where they are expected: in the supplyChain object. 然后,结果列表必须直接在期望的位置构建:在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);

I Hope this matches your expectations. 我希望这符合你的期望。 Anyway, I think this is answer to the question: wrap collections into object SupplyChain. 无论如何,我认为这是问题的答案:将集合包装到对象SupplyChain中。

Cheers 干杯

I have to guess that the "big query returns 2 recordset [...]" is actually a stored procedure whose body consists in 2 SELECT statements (just as suggested in Multiple ResultSets for Association chapter of Mybatis doc ) And that's how you obtain 2 result sets. 我必须猜测“大查询返回2记录集[...]”实际上是一个存储过程,其主体包含2个SELECT语句(正如Mybatis doc中 关联章节的多个ResultSet中所建议的那样)这就是你如何获得2结果集。

You may indeed try to build a single SELECT and map the columns using collections/associations. 您可能确实尝试构建单个SELECT并使用集合/关联映射列。

Or you may bind your destination collections to stored procedure OUT parameters (here is for Oracle): 或者您可以将目标集合绑定到存储过程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;

And here is the Mapper interface (with annotations, you can transpose it all to the XML): 这里是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);

The resultMaps are those you define in the XML. resultMaps是您在XML中定义的那些。

So call the mapper and the SupplyChain bean will be filled when the procedure will have responded. 因此,当程序响应时,调用映射器并填充SupplyChain bean。

Anyway, I wonder what is the behavior difference between working with SELECTs or CURSORs, especially regarding resources management / performance, considering Java eventually works with resultSets. 无论如何,我想知道使用SELECT或CURSOR之间的行为差​​异是什么,特别是关于资源管理/性能,考虑到Java最终可以使用resultSets。 For exemple I wanted to set a custom value for fetchSize option (Oracle default is 10, which is very slow for large result sets (too much java<-->DB round-trips)). 例如,我想为fetchSize选项设置一个自定义值(Oracle默认值为10,对于大型结果集来说非常慢(过多的java < - > DB往返))。 But so far I could not figure out if this statement option is used for bound out-params. 但到目前为止,我无法弄清楚这个语句选项是否用于绑定out-params。

Cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM