2012-03-03 58 views
2

对于新项目,我们决定使用Spring MVC和JdbcTemplate(特别是SimpleJdbcTemplate)来保存域对象。我一直在用这种方法处理的一个问题是如何从SELECT查询中干净地创建对象图。当我从单个表中拉行时,RowMapper机制似乎很好用;当我映射JOIN查询的结果时,我很担心。使用SimpleJdbcTemplate干净地创建域对象的对象图

举一个具体的(尚未完全制造)例如,假设我有在N对1的关系两个实体:

public class Invoice { 
    private Customer customer; 
    ... 
} 

public class Customer { 
    private int id; 
    private String name; 
    ... 
} 

我想能够调用一个selectInvoices()方法在我InvoiceDAO ,并检索一个列表Invoice填充完整形式的Customer实例。相反,我发现自己想做类似下面的事情:

public class Invoice { 
    // this makes me unhappy 
    private int customerId; 
    ... 
} 

干净地做到这一点的最佳做法是什么?我应该咬一口子弹并使用ORM吗?

+0

好问题,如果你不想搅浑你的DAO的或POJO的,那么你将不得不去ORM路线。 – Perception 2012-03-03 17:45:38

回答

2

这正是ORM擅长的。如果你想全部由自己来做,我的诀窍是使用地图来保存客户:

Map<Long, Customer> customersById = new HashMap<Long, Customer>(); 
... 
public Invoice mapRow(ResultSet rs, int rowNum) throws SQLException { 
    Invoice invoice = ... 
    // populate invoice fields 
    Long customerId = rs.getLong("customerId"); 
    Customer c = customersById.get(customerId); 
    if (c == null) { 
     // first time we meet this customer 
     c = ... 
     // populate customer fields from result set 
     customersById.put(customerId, c); 
    } 
    invoice.setCustomer(c); 
} 
+0

我看到这是如何缓解(但并未消除)N + 1 SQL反模式。如果我知道我的“客户”数量很少(或者给定典型输入重复),这似乎是一个很好的解决方案。它不会在我的RowMapper中过多地了解客户表;知识保留在CustomerDAO中。感觉像是失去了指示数据库进行连接的性能和ACID属性的耻辱。这就是妥协的性质,对吧? – nstory 2012-03-03 21:03:55

+0

上述代码的想法正是从一个结果集加载发票给他们的客户,来自一个连接查询,例如'select i。*,c。* from invoice i inner join customer c on i.customer_id = c。 id在哪里......'。我在这里看不到任何N + 1问题。 – 2012-03-03 21:07:59

+0

哦!我读错了你的答案。你是对的:那里没有N + 1个问题。 – nstory 2012-03-03 21:15:00