2012-11-08 30 views
5

मान लें कि मेरे पास दो अलग-अलग संबंधों के साथ एक वस्तु है। बहुत पसंद:एकाधिक एक-से-कई रिश्तों के परिणाम ResetSetExtractor

Customer 1<->M Brands और Customer 1<->M Orders

और कहते हैं कि मेरी वस्तु Customer उन दो वस्तुओं से संबंधित दो सूचियों है करते हैं।

मैंने यह उदाहरण पढ़ा है: http://forum.springsource.org/showthread.php?50617-rowmapper-with-one-to-many-query जो बताता है कि इसे एक-से-कई रिश्ते के साथ कैसे किया जाए।

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

मुझे नहीं लगता कि यह कैसे दोनों के साथ काम करने के लिए शामिल किया गया है: आपकी सुविधा के लिये यहां ResultSetExtractor ओवरराइड है। सबसे साफ दृष्टिकोण क्या होगा? क्या परिस्थितियों के साथ पुनरावृत्ति करने का एक आसान तरीका है? इस मामले में सूचियों की तुलना में सेट बेहतर होगा?

+0

क्या संरचना अपनी मेज है? – soulcheck

+0

यह एक अजीब संरचना है, यह विरासत में है। कोई स्पष्ट संबंध नहीं है जिसने मुझे मानक ओआरएम के विरोध में जेडीबीसी में जाने के लिए मजबूर किया। लेकिन उपयोगकर्ता द्वारा परिभाषित संबंध उर्फ ​​हैं, ग्राहक के पास कई ऑर्डर हो सकते हैं, ग्राहक के पास कई ब्रांड हो सकते हैं। तो उदाहरण के लिए यदि मैंने हाइबरनेट का उपयोग किया है, तो मेरे पास ऑब्जेक्ट्स के रूप में 2 सूचियों के साथ मेरा ऑब्जेक्ट 'ग्राहक' होगा और उन्हें कई लोगों के रूप में एनोटेट किया जाएगा, लेकिन चूंकि मैं सीधे ऊपर की क्वेरी का उपयोग कर रहा हूं और इसमें शामिल हूं, मुझे लगता है कि इसमें दो लगेंगे ऑब्जेक्ट 'ग्राहक' की एक सूची को पॉप्युलेट करने के लिए अलग-अलग प्रश्न, क्योंकि अन्यथा यह एक झुका हुआ परिणामसेट वापस कर देगा। – Nimchip

+0

गैर, बस बताएं कि इस मामले में आपके पास कौन सी टेबल और कॉलम हैं और यदि ब्रांड से आदेशों के लिए एक मजेदार मैपिंग भी है और इसके विपरीत वे पूरी तरह से स्वतंत्र हैं – soulcheck

उत्तर

19

आपके प्रश्न से, मुझे लगता है कि आपके पास तीन टेबल हैं; ग्राहक, ब्रांड, आदेश। यदि आप ग्राहक के ब्रांड और ऑर्डर गुणों को अपने ग्राहक ऑब्जेक्ट में ले जाना चाहते हैं, जहां ब्रांड्स और ऑर्डर के बीच कोई संबंध नहीं है, तो मेरा सुझाव है कि यूनियन क्वेरी का उपयोग करना है।कुछ इस तरह:

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

धन्यवाद, यह वही है जो मैं ढूंढ रहा था। मैं ओआरएम के साथ काम कर रहे यूनियनों और सामान्य रूप से सामान्यीकृत टेबल के बारे में सब भूल गया। – Nimchip

+0

@tkr उन्हें अलग करके आपका क्या मतलब है? – Nimchip

1

अगर मैं वास्तव में यह करना ही था , मैं ResultSetExtractor से अधिक RowCallbackHandler पसंद करेंगे। RowCallbackHandler api और JDBCTemplate api देखें।

इस मामले में आपको परिणामी ग्राहक स्वयं को हैंडलर में संग्रहित करने की आवश्यकता है। सेट डुप्लीकेट को फ़िल्टर करने में मदद कर सकता है।

2

मुझे लगता है कि सभी पंक्तियों को फिर से शुरू करने, दो अलग-अलग वस्तुओं को निकालने और ग्राहक ऑब्जेक्ट के भीतर List<Brand> और List<Order> में जोड़ने के अलावा कोई बेहतर तरीका नहीं है।

तो तुम एक ग्राहक वस्तु में समाप्त होगा:

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

एक mutliple rowmapper के बारे में SpringSource पर एक समस्या हुई थी: 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

मुझे लगता है कि अगर आपको वास्तव में उत्सुकता की आवश्यकता है तो आप इसे सही कर रहे हैं। यदि आपको आलसी लाने की आवश्यकता होगी तो आप रनटाइम के दौरान एक्सेस पर संबंधित ऑर्डर और ब्रांड लोड कर सकते हैं। इस तरह हाइबरनेट और अन्य ओआरएम ढांचे इसे करते हैं। यह आपके परिदृश्य पर निर्भर करता है और आप वस्तु के साथ क्या करते हैं।

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 
जी के बजाए

एक क्वेरी के लिए oing, मेरा सुझाव है कि तीन निम्नलिखित:

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