我有一个域对象,表示数据库表之间的 1:n 关系。
public class ObservationWithData {
private Observation observation;
private Map<Integer,ElementValue> elementValues;
// accessor methods
... }
Observation和ElementValue都包含
private int datetimeId;
private int stationId;
// accessor methods
...
我有一个连接两个表的选择查询。我想使用 resultMap 根据 datetimeId 和 stationId 将 ElementValues 与 Observations 分组,如本(非工作)示例中所示。
<resultMap id="observationWithDataMap" class="ObservationWithData"
groupBy="observation.datetimeId,observation.stationId">
<result property="observation" resultMap="ObservationSql.observationMap" />
<result property="elementValues" resultMap="ElementSql.elementValueMap"/>
</resultMap>
这有两个问题。首先,groupBy 标签不允许嵌套语法,其次,iBATIS 要求 grouped 属性成为 Java Collections API 的一部分,而 Map 不符合该标准。
我可以通过添加 datetimeId 和 stationId 访问器来解决第一个问题,第二个问题可以通过创建一个要写入的集合然后在数据拉取后将所有项目添加到 map 来解决。
<resultMap id="observationWithDataMap" class="ObservationWithData"
groupBy="datetimeId,stationId">
<result property="stationId" column="station_id" />
<result property="datetimeId" column="datetime_id" />
<result property="observation" resultMap="ObservationSql.observationMap" />
<result property="elementValueCollection" resultMap="ElementSql.elementValueMap"/>
</resultMap>
public class ObservationWithData {
private Observation observation;
private Map<Integer,ElementValue> elementValues;
// this collection is used for database retrieval only; do not add to it
private Collection<ElementValue> elementValueCollection;
public void setStationId(int id) { }
public int getStationId() {
return observation==null?0:observation.getStationId();
}
public void setDatetimeId(int id) { }
public int getDatetimeId() {
return observation==null?0:observation.getDatetimeId();
}
public Map<Integer,ElementValue> getElementValues() {
if (elementValues.size()==0 && elementValueCollection.size()>0) {
for (ElementValue val : elementValueCollection) {
elementValues.put(val.getElementId(), val);
}
elementValueCollection.clear();
}
return elementValues;
}
public Collection<ElementValue> getElementValueCollection() {
if (elementValueCollection.size()==0 && elementValues.size()>0) {
elementValueCollection.addAll(elementValues.values());
elementValues.clear();
}
return elementValueCollection;
}
... }
不过,我对这个解决方案不是很满意,因为现在有很多我不希望人们在他们的代码中使用的公共(public)方法。 id setter 是空的,因为这些 id 在观察中设置。我可以让 ObservationWithData 扩展 Observation,但我设计这个类是为了根据 Effective Java 支持组合而不是继承。我也可以以不同的方式同步 map 和集合,但我的想法是让 iBATIS 填充集合,然后在访问 map 时,我会将所有值移入其中,只保留一个引用。
有人可以推荐一个更优雅的解决方案吗?
编辑:
我最终提取了一个服务层来处理这个问题。服务层通过 DAO 进行两次数据库调用,而不是一次;第一个检索所有 Observations,第二个检索所有 ElementValues。它从这些集合构造 ObservationWithData 对象。它还会限制请求,因为这是一个大型数据集。
这有点笨拙且效率低下,因为我是“手动”构建对象。然而,由于这是“隐藏”在服务层中,我觉得它对 API 用户的干扰较小,他们可以使用一个整洁的域对象。
最佳答案
您是否尝试将 DAO 编写为一个 2 阶段过程,首先获取 ObservationWithData 对象,然后用 elementValues 填充它们?它不会针对大量行进行缩放,但根据您需要获取的内容,它现在可能会使它的外部更干净一些。
另一种选择是通过将结果映射到带有 getter 和 setter 的私有(private)对象打包,然后将它们作为不带 setter 的不同类返回给调用者,从而从数据库中获取数据。虽然不确定这是否有帮助,但我认为它甚至可能会给解决方案带来更多困惑。
关于java - 如何在 ibatis 2.3.4 中有效地映射复杂的集合属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5735365/