Как эффективно отобразить сложные свойства коллекции в ibatis 2.3.4 - PullRequest
4 голосов
/ 20 апреля 2011

У меня есть объект домена, который представляет отношение 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, которые получают незагроможденный объект домена для работы.

Ответы [ 2 ]

1 голос
/ 06 июля 2011

Вы пытались написать свой DAO так, чтобы это был двухэтапный процесс, когда вы сначала выбираете объекты ObservationWithData, а затем заполняете их elementValues?Он не будет масштабироваться для огромного числа строк, но в зависимости от того, что вам нужно извлечь, он может сделать его немного чище снаружи.

Другой вариант - выборка данных из базы данных путем сопоставленияприводит к упаковке частных объектов с помощью методов получения и установки, а затем возвращает их вызывающей стороне как другой класс без установщиков.Не уверен, поможет ли это, хотя, я думаю, что это может даже добавить больше беспорядка к решению.

0 голосов
/ 26 сентября 2017

Мы сопоставили свойства сложной коллекции с помощью атрибута groupBy ibatis, как показано ниже -

<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>.

...