2012-11-08 105 views
5

假設我有一個具有兩種不同一對多關係的對象。就像:多個一對多關係ResultSetExtractor

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

而且我們說,我的對象Customer具有與這兩個對象的兩個列表。

我讀過這個例子: 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());; 
    } 
} 

我不認爲它涵蓋了如何使用這兩種工作。什麼是最乾淨的方法?有沒有比迭代條件更簡單的方法?在這種情況下,套餐會比名單更好嗎?

+0

貴的表有什麼結構? – soulcheck

+0

這是一個奇怪的結構,這是一個遺傳的proyect。沒有明確的關係,這迫使我轉向jdbc而不是標準的ORM。但是也有用戶定義的關係,即客戶可能有很多訂單,客戶可能有很多品牌。因此,例如,如果我使用休眠,我會有我的對象'客戶'與2列表作爲屬性,並將它們註釋爲一對多,但因爲我使用直接查詢和連接,我認爲這將需要兩個不同的查詢來填充對象'Customer'的列表,否則它將返回混亂的結果集。 – Nimchip

+0

nono,只是告訴你在這種情況下有什麼表和列,以及是否有從品牌到訂單的功能映射,反之亦然,或者它們是完全獨立的嗎? – soulcheck

回答

19

從你的問題,我假設你有三個表;客戶,品牌,訂單。如果您想將客戶的品牌和訂單屬性提取到您的客戶對象,而品牌和訂單之間沒有關係,我建議使用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()); 
    } 
} 
+1

這是我從這個問題中理解的。仍然我不知道爲什麼不分開查詢和結果集提取器。這會讓他們更容易理解。 – tkr

+0

謝謝,這正是我所期待的。我忘記了所有關於使用ORM和工作正常化表的聯盟。 – Nimchip

+0

@tkr你分開它們是什麼意思? – Nimchip

1

如果我真的不得不這樣做,我寧願RowCallbackHandler超過ResultSetExtractor類。請參閱RowCallbackHandler apiJDBCTemplate api

在這種情況下,你需要自己收集所得的客戶集合中的處理程序。 可以幫助過濾掉重複。

2

我認爲沒有比迭代所有行更好的方法,提取兩個不同的對象並將它添加到Customer對象中的List<Brand>List<Order>

所以,你會在客戶對象結束:

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

有對SpringSource的關於複式RowMapper的一個問題:https://jira.springsource.org/browse/SPR-7698

,但只有一個評論鏈接到一個一對多結果集提取器: 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框架如何實現的。這取決於你的場景以及你如何處理對象。

2

我認爲詹姆斯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 

而不是g卷板機一個查詢,我會建議有以下三種:

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); 
      } 
    } 
}