Пример сопоставления вложенных коллекций Mybatis 3.0.5

#java #collections #mapping #persistence #mybatis

#java #Коллекции #сопоставление #постоянство #mybatis

Вопрос:

Я изучаю возможности сопоставления MyBatis 3.0.5. База данных находится в режиме H2 (1.3.160) в запущенном встроенном режиме. С помощью руководства пользователя я получил простые рабочие части. Но мне трудно сопоставить a Set , который использует a HashMap в качестве резервного хранилища.

Вот код Java для пользовательской коллекции, которая имеет настраиваемое поле set as (упрощенное для краткости)

 public class CustomCollection 
{
    @JsonProperty
    private CustomSet<CustomItem> customItems;

    public CustomCollection()
    {
        customItems = new CustomSet<CustomItem>();
    }

    // other stuff  
}
  

Вот CustomSet код (опять же, упрощенный)

 public class CustomSet<E extends CustomItemInterface> extends AbstractSet<E>
{
    private ConcurrentHashMap<String, E> items;

    public CustomSet()
    {
        items = new ConcurrentHashMap<String, E>();
    }

    // other stuff  
}
  

Вот интерфейс сопоставления:

 public interface CustomCollectionMapper 
{
    CustomCollection select(@Param("somename") String s1, @Param("someothername") String s2);
}
  

Это код, который выполняет вызов в Mybatis framework:

 SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) servletContext.getAttribute("SqlSessionFactory");
SqlSession session = sqlSessionFactory.openSession();
CustomCollection coll = null;
try 
{ 
    CustomCollectionMapper mapper = session.getMapper(CustomCollectionMapper.class);
    coll = mapper.select(param1, param2);
} 
finally 
{ 
    session.close(); 
} 
  

Вот что я мог бы придумать с отображением XML до сих пор:

 <select id="select" resultMap="CustomCollectionMapping">
-- What goes here???
</select>

<resultMap type="com.example.CustomCollection" id="CustomCollectionMapping">
  <association property="customItems" javaType="com.example.customSet">
    <collection property="items" javaType="HashMap" ofType="com.example.CustomItem" select="selectCustomItems">
    </collection>
  </association>
</resultMap>

<select id="selectCustomItems" parameterType="map" resultType="com.example.CustomItem">  
  -- SQL query to return multiple CustomItem rows
</select>  
  

Через различные итерации я получил ошибку «слишком много результатов», какую-то другую ошибку или ничего (null возвращается из вызова mapper), но никогда не получал нужного мне результата. Код SQL отлично работает сам по себе, и если я запрошу список с помощью простого оператора select, я получу обратно строки и ArrayList . Проблема, с которой я сталкиваюсь, заключается в правильном заполнении вложенных объектов коллекции.

Я много раз читал руководство, искал примеры, но не мог найти правильный XML-файл сопоставления для этой цели. Я был бы признателен, если кто-нибудь сможет мне помочь или указать мне источник, который может помочь.

Заранее спасибо за всю помощь.

Ответ №1:

Это мой рабочий пример:

 <resultMap id="categoryPreferenceValueMap" type="SyncCategoryPreferenceValueModel">
         <id property="preferenceTypeId" column="preference_type_id" />
         <result property="title" column="title"/>
         <result property="index" column="type_index"/>
          <result property="updatedAt" column="category_updated_at" />
          <collection property="preferences" column="p_preference_id" ofType="SyncPreferenceModel" >
            <id property="preferenceId" column="p_preference_id" />
            <result property="title" column="p_preference_title" />
            <result property="index" column="preference_index" />
            <result property="updatedAt" column="preference_updated_at" />
            <collection property="preferenceValues" column="p_v_preference_value_id"  ofType="SyncPreferenceValueModel"  >
                <id property="preferenceValueId" column="p_v_preference_value_id" />
                <result property="preferenceValue" column="p_v_preference_value" />
                <result property="updatedAt" column="preference_value_updated_at" />
            </collection>  
         </collection>
    </resultMap>
  

Это мой запрос

 <select id="getPrefersenceWithValues" resultMap="categoryPreferenceValueMap">
    SELECT  
        PT.preference_type_id, PT.title, PT.type_index,PT.updated_at as  category_updated_at,
        P.preference_id as p_preference_id , P.title as p_preference_title  ,P.index as preference_index,

        P.updated_at as preference_updated_at,

        PV.preference_value_id as p_v_preference_value_id ,PV.preference_value as p_v_preference_value  

    FROM preference_types PT
    INNER JOIN preferences P ON PT.preference_type_id=P.preference_type_id 
        INNER JOIN preference_values PV ON P.preference_id=PV.preference_id 

    ORDER BY type_index
</select>
  

И вывод:

  [
    {
      "preferenceTypeId": "1",
      "title": "abc BASICS",
      "index": "1",
      "updatedAt": 1,
      "preferences": [
        {
          "preferenceId": "1",
          "title": "xyz xyz",
          "preferenceTypeId": null,
          "gender": null,
          "index": 1,
          "updatedAt": 1,
          "preferenceValues": [
            {
              "preferenceId": null,
              "preferenceValueId": "2",
              "preferenceValue": "30-60",
              "gender": null,
              "updatedAt": 0
            },
            {
              "preferenceId": null,
              "preferenceValueId": "1",
              "preferenceValue": "0-30",
              "gender": null,
              "updatedAt": 0
            }
          ]
        }
      ]
    }
  ]
  

Ответ №2:

Возможно, вы захотите попробовать пользовательский обработчик результатов. Я думаю, что ваш пользовательский набор должен работать. Я собираюсь продолжить расследование, я обновлю, если что-то найду.

Ответ №3:

Похоже ResultHandler , это может сработать, но это заставляет меня писать много кода, оставляя преимущества фабрики сопоставления XML. Также меня беспокоит тот факт, что обработчик будет вызываться один раз для каждой возвращаемой строки.

Я узнал из сообщения в группе пользователей mybatis, что Mybatis на самом деле не будет делать то, что я хочу (даже если я избавлюсь от посредника CustomSet , не похоже, что Mybatis сможет заполнить hashmap так, как мне нужно), поэтому я решил пойти с тем, что ОПв этой теме делается следующее: получение списка и заполнение самого HashMap себя. Это позволит мне получать объекты через сопоставление и с небольшим количеством кода HashMap заполнять необходимые данные.

Ответ №4:

однажды у меня была такая же проблема. Как предлагает @Andy Pryor, вы можете использовать ResultHandler . Но, как я только что «разделил» ваши данные.

Я имею в виду переместить ваши данные, которые будут находиться в a Map , в другой класс. А затем свяжите ваш Set с этим новым классом.

 <resultMap type="com.example.CustomCollection" id="CustomCollectionMapping">
    <collection property="items" javaType="java.util.TreeSet"
         ofType="com.example.NewCustomItem" select="selectCustomItems"/>
</resultMap>
  

Обратите внимание, вот com.example.NewCustomItem этот новый класс. Вам просто нужно написать еще один mapper для этого класса, и он работает.

Но если вам действительно нужно Map использовать ResultHandler тогда.