我有一个域对象,它表示数据库表之间的 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 是 noops,因为这些 id 是在观察中设置的。我可以让 ObservationWithData 扩展 Observation,但是我设计了这个类来支持每个 Effective Java 的组合而不是继承。我也可以以不同的方式同步 map 和集合,但我的想法是让 iBATIS 填充集合,然后当访问 map 时,我会将所有值移动到其中,只保留一个引用。

有人可以推荐一个更优雅的解决方案吗?

编辑:

我最终提取了一个服务层来处理这个问题。服务层通过 DAO 进行两次数据库调用,而不是一次;第一个检索所有观察,第二个检索所有元素值。它从这些集合构造 ObservationWithData 对象。它还会限制请求,因为这是一个大型数据集。

这有点笨拙且效率低下,因为我正在“手动”构建对象。但是,由于这是“隐藏”在服务层中的,我觉得它对 API 用户的干扰较小,他们可以使用整洁的域对象来使用。

最佳答案

您是否尝试编写您的 DAO,以便这是一个 2 阶段过程,您首先获取 ObservationWithData 对象,然后用 elementValues 填充它们?它不会针对大量行进行缩放,但根据您需要获取的内容,它现在可能会使其在外部更干净一些。

另一种选择是通过将结果映射到带有 getter 和 setter 的私有(private)对象打包来从数据库中获取数据,然后将它们作为不同的类返回给调用者,而没有 setter。不确定这是否会有所帮助,我认为它甚至可能会给解决方案添加更多困惑。

关于java - 如何在 ibatis 2.3.4 中有效地映射复杂的集合属性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5735365/

10-09 08:00