2012-11-08 22 views
5

Diyelim ki, iki farklı bire çok ilişkisi olan bir nesneyim var. Çok gibi:birden çok çoklu ilişki ResultSetExtractor

Customer 1<->M Brands ve

Customer 1<->M Orders Ve benim nesne Customer bu iki nesne ile ilgili iki listeyi sahip olduğunu varsayalım.

Ben bu örneği okudum: http://forum.springsource.org/showthread.php?50617-rowmapper-with-one-to-many-query tek bire çok ilişkisi ile nasıl yapılacağını açıklar.

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

Ben ikisi ile çalışmak nasıl kapsar sanmıyorum: Kullanım rahatlığı için buraya ResultSetExtractor kılma. En temiz yaklaşım ne olurdu? Koşullarla tekrarlamaktan daha basit bir yol var mı? Bu durumda listelerden daha iyi olur mu? Gerçekten bunu yapmak zorunda Eğer

+0

tablo hangi yapı var? – soulcheck

+0

Bu garip bir yapı, bu kalıtsal bir proyect. Standart bir ORM'nin aksine jdbc'ye taşınmam için beni zorlayan açık bir ilişki yoktur. Ancak kullanıcı tanımlı ilişkiler var, bir müşterinin birçok siparişi olabilir, bir müşterinin çok sayıda markası olabilir. Örneğin, örneğin hazırda bekletme özelliğini kullanırsam, "Müşteri" nesnelerini 2 liste olarak alırdım ve bunlara birden çok tane ekleyebilirdim, ancak düz bir sorgu kullanıyor ve katıldığımdan iki tane alacağımı düşünüyorum. "Müşteri" nesnesinin bir listesini doldurmak için farklı sorgular, aksi halde bir karmaşayı döndürür. – Nimchip

+0

nono, sadece bu durumda hangi tabloları ve sütunları olduğunu ve ayrıca markalardan siparişlere ve tersi bir eşzamanlı haritalama varsa ya da tamamen bağımsız – soulcheck

cevap

19

Sorunuzda, üç tablonuz olduğunu varsayalım; Müşteri, Markalar, Siparişler. Markaların Marka ve Sipariş özelliklerini müşteri nesnesine getirmek istiyorsanız, Markalar ve Siparişler arasında bir ilişki olmadığı yerde, önerdiğim bir UNION sorgusu kullanmaktır.Böyle bir şey:

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 

Sorgu:

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) 

Kişisel ResultSetExtractor olacak:

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

Bu sorudan anladım. Yine de neden sorguları ve sonuçları çıkarıcıları ayırmamayı merak ediyorum. Onları çok daha anlaşılır hale getirirdi. – tkr

+0

Teşekkürler, bu tam olarak aradığım şey. ORM'ler ile çalışan sendikalar ve tereddütlü normalleştirilmiş tablolar hakkında her şeyi unuttum. – Nimchip

+0

@tkr Onları ayırarak ne demek istiyorsun? – Nimchip

1

, ben ResultSetExtractor üzerinde RowCallbackHandler tercih ediyorum. Bkz RowCallbackHandler api ve JDBCTemplate api.

Bu durumda, ortaya çıkan Müşteriler koleksiyonunu kendiniz işleyicide toplamanız gerekir. , kopyaları filtrelemeye yardımcı olabilir.

2

Sanırım tüm satırlar üzerinde yineleme yapmak, iki farklı nesneyi ayıklamak ve bir List<Brand> ve List<Order> Müşteri nesnesine eklemek daha iyi bir yol yoktur.

Yani bir müşteri nesnesinde sona ereceğini: Bir mutliple rowmapper ilişkin SpringSource üzerinde bir hata tespit edildi

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

: https://jira.springsource.org/browse/SPR-7698

ancak bağlantı sadece bir yorum var bire-birçok resultset çıkarıcı: https://github.com/SpringSource/spring-data-jdbc-ext/blob/master/spring-data-jdbc-core/src/main/java/org/springframework/data/jdbc/core/OneToManyResultSetExtractor.java

Eğer gerçekten istekli getirme gerekiyorsa doğru yaptığınızı düşünüyorum. Tembel getirme işlemine ihtiyacınız varsa, çalışma sırasında ilgili siparişleri ve markaları erişime yükleyebilirsiniz. Hibernate ve diğer ORM çerçeveleri bunu böyle yapıyor. Senaryonuza ve nesneyle ne yaptığınıza bağlı.

2

ben onun cevabını James Jithin tarafından açıklanan modeli varsayalım:

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 

yerine g bir Query için meler, öneririm üç aşağıdadır:

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 

Kişisel RowCallbackHandlers olacaktı:

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); 
      } 
    } 
} 
İlgili konular