У меня есть объект домена, который представляет отношение 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, как в этом (нерабочем) примере.
<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 требует, чтобы сгруппированное свойство было частью API коллекций Java, и 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;
}
... }
Однако я не очень доволен этим решением, потому что сейчас есть много открытых методов, которые я не хочу, чтобы люди использовали в своем коде. Установщики идентификаторов являются noops, потому что эти идентификаторы устанавливаются в наблюдении. Я мог бы использовать ObservationWithData для расширения Observation, но я разработал этот класс, чтобы отдавать предпочтение композиции по сравнению с наследованием для Effective Java . Я также мог бы по-разному синхронизировать карту и коллекцию, но идея заключается в том, что я позволю iBATIS заполнить коллекцию, а затем при доступе к карте я перенесу в нее все значения, сохраняя только одну ссылку.
Может кто-нибудь порекомендовать более элегантное решение?
Редактировать:
Я закончил тем, что извлек сервисный слой, чтобы справиться с этим. Уровень обслуживания выполняет два вызова базы данных через DAO вместо одного; первая возвращает все наблюдения, а вторая - все ElementValues. Он создает объекты ObservationWithData из этих коллекций. Это также регулирует запрос, поскольку это большой набор данных.
Это немного неуклюже и неэффективно, потому что я "вручную" строю объекты. Однако, поскольку это «скрыто» на уровне сервисов, я чувствую, что оно менее навязчиво для пользователей API, которые получают незагроможденный объект домена для работы.