我有一个域对象,表示数据库表之间的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将ElementValues与基于datetimeId和stationId的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要求分组属性是Java Collections API的一部分,而Map不符合该标准。
我可以通过添加datetimeId和stationId访问器来解决第一个问题,第二个项目可以通过创建要写入的集合来解决,然后在数据提取后将所有项目添加到地图中。
<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;
}
... }
我对这个解决方案不是很满意,因为现在有很多公共方法我不希望人们在他们的代码中使用。 id setter是noops,因为这些id在观察中被设置。我可以使用ObservationWithData扩展Observation,但是我设计了这个类以支持每个 Effective Java 的继承的组合。我也可以不同地同步地图和集合,但我的想法是我会让iBATIS填充集合,然后当访问地图时,我会将所有值移入其中,只保留一个引用。
有人可以推荐更优雅的解决方案吗?
修改:
我最终提取了一个服务层来处理这个问题。服务层通过DAO而不是一个进行两次数据库调用;第一个检索所有Observations,第二个检索所有ElementValues。它从这些集合构造ObservationWithData对象。它还会限制请求,因为这是一个大型数据集。
这有点笨拙且效率低下,因为我“手动”构建对象。但是,由于这是“隐藏”在服务层中,我觉得它对API用户的干扰较小,他们可以使用整洁的域对象。
答案 0 :(得分:1)
您是否尝试编写DAO以便这是一个两阶段的过程,首先获取ObservationWithData对象然后用elementValues填充它们?它不会扩展到大量的行,但取决于你需要获取它可能会使它在外面变得更干净。
另一种选择是通过将结果映射到具有getter和setter的包私有对象,然后将它们作为不带有setter的不同类返回给调用者来从数据库中获取数据。不确定这是否会有所帮助,我认为它甚至可能会给解决方案带来更多麻烦。
答案 1 :(得分:0)
我们使用ibatis的groupBy属性映射了复杂的集合属性,如下所示 -
<resultMap id="actionResultsMap" class="Content" groupBy="objectID">
<result property="objectID" column="object_id"/>
<result property="bvReferenceNo" column="reference_no"/>
.......
<result property="countryId" resultMap="MyActions.countryMap"/>
</resultMap>
<resultMap id="countryMap" class="java.lang.Integer">
<result property="value" column="country"/>
</resultMap>
<select id="myActions" resultMap="actionResultsMap"
parameterClass="java.util.HashMap">
SELECT
object_id,
reference_no,
........
country
from sysObject so left outer join countryTable ct on ct.object_id = so.object_id
</select>
此处countryId的类型为List<Integer>
。