14

質問は、Spring jdbc を使用して詳細を熱心に取得したいマスター/詳細シナリオでの RowMapper のベスト プラクティスの使用法に関するものです。

Invoice クラスと InvoiceLine クラスの両方があるとします。

public class Invoice{
    private BigDecimal invId;
    private Date invDate;
    private List<InvoiceLine> lines;
}
public class InvoiceLine{
    private int order;
    private BigDecimal price;
    private BigDecimal quantity;
}

行マッパーでSpring Jdbcを使用する場合、通常、

public class InvoiceMapper implements RowMapper<Invoice>{
    public Invoice mapRow(ResultSet rs, int rowNum) throws SQLException {
         Invoice invoice = new Invoice();
         invoice.setInvId(rs.getBigDecimal("INVID"));
         invoice.setInvDate(rs.getDate("INVDATE"));
         return invoice;
    }
}

問題は、この請求書インスタンスに関連する InvoiceLine を熱心に取得したいということです。rowmapper クラスでデータベースにクエリを実行してもよろしいですか? または、別の方法を好む人はいますか?以下のパターンを使用していますが、満足していません。

public class InvoiceMapper implements RowMapper<Invoice>{
    private JdbcTemplate jdbcTemplate;
    private static final String SQLINVLINE=
            "SELECT * FROM INVOICELINES WHERE INVID = ?";

    public Invoice mapRow(ResultSet rs, int rowNum) throws SQLException {
         Invoice invoice = new Invoice();
         invoice.setInvId(rs.getBigDecimal("INVID"));
         invoice.setInvDate(rs.getDate("INVDATE"));
         invoice.setLines(jdbcTemplate.query(SQLINVLINE, 
                          new Object[]{invoice.getInvId},new InvLineMapper());

         return invoice;
    }
}

このアプローチには何か問題があると感じていますが、より良い方法は得られませんでした。誰かがなぜこれが悪いデザインなのか、もしそうなら正しい使い方を教えてくれたら嬉しいです.

4

4 に答える 4

18

ResultSetExtractorは、これを行うためのより良いオプションです。両方のテーブルを結合する 1 つのクエリを実行し、結果セットを反復処理します。同じ請求書に属する複数の行を集計するには、いくつかのロジックが必要です。これには、請求書 ID で並べ替えて ID がいつ変更されたかを確認するか、以下の例に示すようなマップを使用します。

jdbcTemplate.query("SELECT * FROM INVOICE inv JOIN INVOICE_LINE line " +
   + " on inv.id = line.invoice_id", new ResultSetExtractor<List<Invoice>>() {

    public List<Invoice> extractData(ResultSet rs) {
        Map<Integer,Invoice> invoices = new HashMap<Integer,Invoice>();
        while(rs.hasNext()) {
            rs.next();
            Integer invoiceId = rs.getInt("inv.id");
            Invoice invoice = invoces.get(invoiceId);
            if (invoice == null) {
               invoice = invoiceRowMapper.mapRow(rs);
               invoices.put(invoiceId,invoice);
            }
            InvoiceItem item = invLineMapper.mapRow(rs);
            invoice.addItem(item);  
        }
        return invoices.values();
    }


});
于 2012-07-12T17:11:11.463 に答える
4

ここで1 + n問題を再現したもの。

それを解決するには、外部クエリを結合に変更してから、ループを手作りして、フラット結合の結果セットを解析する必要がありますInvoice 1 -> * InvLine

List<Invoice> results = new ArrayList<>();
jdbcTemplate.query("SELECT * FROM INVOICE inv JOIN INVOICE_LINE line on inv.id = line.invoice_id", null, 
    new RowCallbackHandler() {
    private Invoice current = null;
    private InvoiceMapper invoiceMapper ;
    private InvLineMapper lineMapper ;

    public void processRow(ResultSet rs) {
        if ( current == null || rs.getInt("inv.id") != current.getId() ){
            current = invoiceMapper.mapRow(rs, 0); // assumes rownum not important
            results.add(current);
        }
        current.addInvoiceLine( lineMapper.mapRow(rs, 0) );
    }
}

私は明らかにこれをコンパイルしていません...うまくいけば、あなたはアイデアを得るでしょう。別のオプションがあり、休止状態または JPA 実装を使用します。これらは、この種のことをすぐに実行できるため、時間を大幅に節約できます。

訂正:ResultSetExtractor@gkamalが彼の答えで使用したように実際に使用する必要がありますが、全体的なロジックは依然として有効です。

于 2012-07-12T15:56:40.577 に答える
0

最も簡単な方法

このライブラリを簡単に使用できます.SimpleFlatMapperはすでにその問題を解決しています. ResultSetExtractorを使用して を作成するだけですJdbcTemplateMapperFactory

import org.simpleflatmapper.jdbc.spring.JdbcTemplateMapperFactory;

private final ResultSetExtractor<List<Invoice>> resultSetExtractor = 
    JdbcTemplateMapperFactory
        .newInstance()
        .addKeys("id") // the column name you expect the invoice id to be on
        .newResultSetExtractor(Invoice.class);

String query = "SELECT * FROM INVOICE inv JOIN INVOICE_LINE line on inv.id = line.invoice_id"

List<Invoice> results = jdbcTemplate.query(query, resultSetExtractor);

この依存関係をpom.xml

<dependency>
    <groupId>org.simpleflatmapper</groupId>
    <artifactId>sfm-springjdbc</artifactId>
    <version>8.2.1</version>
</dependency>

参照する記事は次のとおりです-https://arnaudroger.github.io/blog/2017/06/13/jdbc-template-one-to-many.html

さまざまな使用例を次に示します - https://github.com/arnaudroger/SimpleFlatMapper/blob/master/sfm-springjdbc/src/test/java/org/simpleflatmapper/jdbc/spring/test/JdbcTemplateMapperFactoryTest.java

于 2020-04-09T05:32:45.667 に答える