8

2 つの異なる 1 対多の関係を持つオブジェクトがあるとします。よく似ています:

Customer 1<->M BrandsCustomer 1<->M Orders

my オブジェクトCustomerには、これら 2 つのオブジェクトに関連する 2 つのリストがあるとします。

私はこの例を読みました: http://forum.springsource.org/showthread.php?50617-rowmapper-with-one-to-many-query は、単一の一対多の関係でそれを行う方法を説明しています。便宜上、ResultSetExtractorオーバーライドを次に示します。

private class MyObjectExtractor implements ResultSetExtractor{

    public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
        Map<Integer, MyObject> map = new HashMap<Integer, MyObject>();
        MyObject myObject = null;
        while (rs.next()) {
            Integer id = rs.getInt("ID);
            myObject = map.get(id);
          if(myObject == null){
              String description = rs,getString("Description");
              myObject = new MyObject(id, description);
              map.put(id, myObject);
          }
      MyFoo foo = new MyFoo(rs.getString("Foo"), rs.getString("Bar"));
      myObject.add(myFoo);
        }
        return new ArrayList<MyObject>(map.values());;
    }
}

両方を扱う方法をカバーしているとは思いません。最もクリーンなアプローチは何ですか?条件を反復するよりも簡単な方法はありますか? この場合、セットはリストよりも適していますか?

4

4 に答える 4

23

あなたの質問から、私はあなたが3つのテーブルを持っていると思います。顧客、ブランド、注文。ブランドと注文の間に関係がない、顧客のブランドと注文のプロパティを顧客オブジェクトにフェッチする場合は、UNIONクエリを使用することをお勧めします。このようなもの:

TBL_CUSTOMER
------------
CUSTOMER_ID
CUSTOMER_ACCOUNT_NO
CUSTOMER_NAME

TBL_CUSTOMER_BRANDS
-------------------
CUSTOMER_BRAND_ID            - UK
BRAND_NAME
CUSTOMER_ID                  - FK

TBL_ORDERS
-------------------
ORDER_ID                     - UK
CUSTOMER_ID                  - FK

クエリ:

SELECT CUS.*, BRANDS.CUSTOMER_BRAND_ID COL_A, BRANDS.BRAND_NAME COL_B, 1 IS_BRAND FROM TBL_CUSTOMER CUS JOIN TBL_CUSTOMER_BRANDS BRANDS ON (CUS.CUSTOMER_ID = BRANDS.CUSTOMER_ID)
UNION ALL
SELECT CUS.*, ORDERS.ORDER_ID, '', 0 IS_BRAND FROM TBL_CUSTOMER CUS JOIN TBL_ORDERS ORDERS ON (CUS.CUSTOMER_ID = ORDERS.CUSTOMER_ID)

ResultSetExtractorは次のようになります。

private class MyObjectExtractor implements ResultSetExtractor{

    public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
            Map<Long, Customer> map = new HashMap<Long, Customer>();

        while (rs.next()) {
            Long id = rs.getLong("CUSTOMER_ID");
            Customer customer = map.get(id);
            if(customer == null){
                customer = new Customer();
                customer.setId(id);
                customer.setName(rs.getString("CUSTOMER_NAME"));
                customer.setAccountNumber(rs.getLong("CUSTOMER_ACCOUNT_NO"));
                map.put(id, customer);
                    }

            int type = rs.getInt("IS_BRAND");
            if(type == 1) {
                List brandList = customer.getBrands();
                if(brandsList == null) {
                    brandsList = new ArrayList<Brand>();
                    customer.setBrands(brandsList);
                }
                Brand brand = new Brand();
                brand.setId(rs.getLong("COL_A"));
                brand.setName(rs.getString("COL_B"));
                brandsList.add(brand);
            } else if(type == 0) {
                List ordersList = customer.getOrders();
                if(ordersList == null) {
                    ordersList = new ArrayList<Order>();
                    customer.setOrders(ordersList);
                }
                Order order = new Order();
                order.setId(rs.getLong("COL_A"));
                ordersList.add(order);
            }
        }
        return new ArrayList<Customer>(map.values());
    }
}
于 2012-11-27T12:04:52.453 に答える
3

すべての行を反復処理し、2 つの異なるオブジェクトを抽出して Customer オブジェクト内のList<Brand>andに追加するよりも良い方法はないと思います。List<Order>

したがって、顧客オブジェクトになります。

public class Customer {
     private List<Brand> brands;
     private List<Order> orders;
....
}

複数の行マッパーに関する SpringSource の問題がありました: https://jira.springsource.org/browse/SPR-7698

ただし、1 対多の結果セット エクストラクタにリンクするコメントは 1 つだけです: https://github.com/SpringSource/spring-data-jdbc-ext/blob/master/spring-data-jdbc-core/src/main/ java/org/springframework/data/jdbc/core/OneToManyResultSetExtractor.java

本当に熱心なフェッチが必要な場合は、正しくやっていると思います。遅延フェッチが必要な場合は、実行時にアクセス時にそれぞれの注文とブランドをロードできます。これが、Hibernate やその他の ORM フレームワークが行う方法です。それは、シナリオとオブジェクトで何をするかによって異なります。

于 2012-11-27T11:41:02.287 に答える
2

James Jithin の回答で説明されているモデルを想定しています。

TBL_CUSTOMER
------------
CUSTOMER_ID
CUSTOMER_ACCOUNT_NO
CUSTOMER_NAME

TBL_CUSTOMER_BRANDS
-------------------
CUSTOMER_BRAND_ID            - UK
BRAND_NAME
CUSTOMER_ID                  - FK

TBL_ORDERS
-------------------
ORDER_ID                     - UK
CUSTOMER_ID                  - FK

1 つのクエリを使用する代わりに、次の 3 つをお勧めします。

SELECT CUS.* FROM TBL_CUSTOMER CUS 

SELECT BRANDS.CUSTOMER_ID, BRANDS.CUSTOMER_BRAND_ID, BRANDS.BRAND_NAME FROM TBL_CUSTOMER_BRANDS BRANDS

SELECT ORDERS.CUSTOMER_ID, ORDERS.ORDER_ID FROM TBL_ORDERS ORDERS 

RowCallbackHandlers は次のようになります。

private class CustomerRowCallbackHandler  implements RowCallbackHandler {

    private final Map<Long, Customer> customerMap;

    public BrandRowCallbackHandler(Map<Long, Customer> customerMap) { this.customerMap = customerMap}

    public void processRow(ResultSet rs) throws SQLException {
            Long id = rs.getLong("CUSTOMER_ID");
            Customer customer = map.get(id);
            if(customer == null){
                customer = new Customer();
                customer.setId(id);
                customer.setName(rs.getString("CUSTOMER_NAME"));
                customer.setAccountNumber(rs.getLong("CUSTOMER_ACCOUNT_NO"));
                map.put(id, customer);
                    }
    }
}

private class BrandRowCallbackHandler implements RowCallbackHandler {

    private final Map<Long, Customer> customerMap;

    public BrandRowCallbackHandler(Map<Long, Customer> customerMap) { this.customerMap = customerMap}

    public void processRow(ResultSet rs) throws SQLException {
            Long id = rs.getLong("CUSTOMER_ID");
            Customer customer = map.get(id);
            if(customer != null){
                List brandList = customer.getBrands();
                if(brandsList == null) {
                    brandsList = new ArrayList<Brand>();
                    customer.setBrands(brandsList);
                }
                Brand brand = new Brand();
                brand.setId(rs.getLong("CUSTOMER_BRAND_ID"));
                brand.setName(rs.getString("CUSTOMER_BRAND_NAME"));
                brandsList.add(brand);
            } 
    }
}

private class OrderRowCallbackHandler implements RowCallbackHandler {

    private final Map<Long, Customer> customerMap;

    public OrderRowCallbackHandler(Map<Long, Customer> customerMap) { this.customerMap = customerMap}

    public void processRow(ResultSet rs) throws SQLException {
            Long id = rs.getLong("CUSTOMER_ID");
            Customer customer = map.get(id);
            if(customer != null){
                List ordersList = customer.getOrders();
                if(ordersList == null) {
                    ordersList = new ArrayList<Order>();
                    customer.setOrders(ordersList);
                }
                Order order = new Order();
                order.setId(rs.getLong("ORDER_ID"));
                ordersList.add(order);
            }
    }
}
于 2012-11-28T06:56:19.773 に答える
1

本当にそうしなければならないのであれば、 ResultSetExtractorよりもRowCallbackHandlerを好むでしょう。RowCallbackHandler apiおよびJDBCTemplate apiを参照してください。

この場合、ハンドラーで結果の Customers コレクションを自分で収集する必要があります。 セットは、重複を除外するのに役立ちます。

于 2012-11-21T15:46:27.817 に答える