8

假设我有一个具有两个不同的一对多关系的对象。很像:

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

我不认为它涵盖了如何与两者一起工作。什么是最干净的方法?有没有比条件迭代更简单的方法?在这种情况下,集合会比列表更好吗?

4

4 回答 4

23

根据您的问题,我假设您有三张桌子;客户、品牌、订单。如果您想将 Customer 的 Brands 和 Orders 属性获取到您的客户对象,而 Brands 和 Orders 之间没有关系,我建议使用 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

我认为没有比遍历所有行、提取两个不同的对象并将其添加到Customer 对象中的List<Brand>和中更好的方法了。List<Order>

所以你最终会得到一个客户对象:

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

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

如果您真的需要急切的获取,我认为您做对了。如果您需要延迟获取,您可以在运行时加载相应的订单和品牌。这就是 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

我建议不要使用一个查询,而是建议以下三个:

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

如果我真的必须这样做,我更喜欢RowCallbackHandler而不是ResultSetExtractor。请参阅RowCallbackHandler apiJDBCTemplate api

在这种情况下,您需要自己在处理程序中收集生成的客户集合。 集合可以帮助过滤掉重复项。

于 2012-11-21T15:46:27.817 回答