3

簡単な問題の説明

複数の結果セットのガイドラインに従い、この回答の助けを借りて、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 つのコレクションを取得しました。しかし、宣言された戻り値の代わりに、実行時に内部リストに2つの要素が含まれている場所List<SupplyChain>を実際に取得しました:List<List>

  • 0要素はList<SupplyChainEdge>
  • と 1 番目: List<SupplyChainNode>.

この生のコレクションをオブジェクトにラップするにはどうすればよいSupplyChainですか?

4

2 に答える 2

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 にラップします。

乾杯

于 2016-10-27T15:28:26.970 に答える
2

「大きなクエリが2つのレコードセットを返す[...]」は、実際には本体が2つのSELECTステートメントで構成されるストアドプロシージャであると推測する必要があります(Mybatisドキュメントの複数のResultSets for Associationの章で示唆されているように)そして、それが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);

resultMap は、XML で定義したものです。

したがって、マッパーを呼び出すと、プロシージャーが応答したときに SupplyChain Bean が満たされます。

とにかく、Javaが最終的にresultSetsで動作することを考えると、特にリソース管理/パフォーマンスに関して、SELECTまたはCURSORでの動作の動作の違いは何だろうと思います。たとえば、fetchSize オプションのカスタム値を設定したいと考えていました (Oracle のデフォルトは 10 で、大きな結果セットでは非常に遅くなります (Java<-->DB ラウンドトリップが多すぎます))。しかし、これまでのところ、このステートメント オプションがバインドされた out-params に使用されているかどうかはわかりませんでした。

乾杯。

于 2016-10-27T09:41:58.123 に答える