15

我正在使用 Spring JDBC,但我有点不确定如何处理多个一对多关系(或多对多)。在这种情况下,我将一个存储库注入到我的一个结果提取器中,以便我可以检索它的关联。这是这样做的方法吗?不好吗?还有其他更好的方法吗?

注意:我省略了存储库的注入

public class SomeResultSetExtractor implements ResultSetExtractor {

  public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
    List result = new LinkedList();

    while (rs.next()) {
        SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2));
        result.add(object);

        List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId);
        object.setOtherObjects(otherObjects);
        // and so on
    }

    return result;

  }
}

好吧,所以在阅读了 Dmytro Polivenok 的答案后,我改为改为 RowMapper 界面,我目前正在使用其他存储库来填充所有关联,就像我在示例中显示的那样。这是一个好方法吗?

4

2 回答 2

5

我认为 Spring JDBC 和 SQL 查询的一个好的做法是对每个实体使用一个查询。

例如假设这个模型:

  • 客户(customerId、姓名、年龄……)
  • 地址(customerId、类型、街道、城市……)
  • PaymentOption (customerId, cardnumber, cardtype, ...)

  • 客户 1---* 地址

  • 客户 1---* PaymentOption

我将构建 3 个查询、3 个 Daos、3 个 ResultSetExtractors/RowcallbackHandlers:

  • CustomerDao 与 readCustomerData(客户或列表)
  • 带有 readAddressForCustomer(客户或列表)的 AddressDao
  • PaymentOptionDao 与 readPaymentOptionsForCustomer(客户或列表)

如果您将在 1 个查询中进行烘焙,则必须构建一些逻辑来恢复笛卡尔积。

  • 即,如果客户有 3 个地址和 2 个付款选项,则查询将返回 6 行。
  • 如果 Address 或 PaymentOption 没有自己的主键,这将变得非常困难。

对于多对多:

  • 客户 * --recommends-- * 产品

我可能会建立:

  • CustomerDao.readRecommendationsAndProductKeys
  • getDistinctListOfProductKeysFromRecommendations
  • ProductDao.readProducts
  • replaceProductKeysByProductsOnRecommendations

像这样你可以重用 ProductDao.readProducts

  • 客户 * --buys-- * 产品或
  • 产品组 1---* 产品
于 2013-03-28T05:58:31.687 回答
4

我认为你的代码可以工作,但这里关注的是 ResultSetExtractor 的使用,它主要用于 JDBC 框架本身,并且在大多数情况下,文档建议使用 RowMapper。

因此,替代方法是在您的 DAO 中使用方法来选择和映射父对象。然后为每个对象调用其他存储库或选择和映射子对象的私有方法,然后根据您的关系类型(单向或双向)将子对象与父对象链接。这种方法还可以让您控制是否要加载子对象。

例如,您可以检查具有SimpleJdbcClinic 类的 Spring PetClinic 应用程序

如果你可以使用其他框架,你可以考虑mybatis,它更多的是关于映射,允许你控制你的 SQL 代码。

于 2013-03-19T21:16:11.783 回答