Mybatis 3.0.5嵌套集合映射示例

时间:2011-10-05 15:14:40

标签: java collections mapping persistence mybatis

我正在调查MyBatis 3.0.5的映射工具。运行嵌入式模式时数据库为H2(1.3.160)。在用户手册的帮助下,我得到了直截了当的部分。但是我很难映射使用Set作为后备存储的HashMap

以下是将自定义设置为字段的自定义集合的Java代码(为简洁起见而简化)

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框架的代码:

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>  

通过各种迭代,我得到“太多结果”错误,一些其他错误或什么都没有(从mapper调用返回null)但从来没有我需要的结果。 SQL代码本身工作正常,如果我要求一个带有简单select语句的List,我会得到行和ArrayList。我遇到的问题是正确填充嵌套集合对象。

我已多次阅读本手册,搜索了示例但我无法为此目的提供正确的映射XML。如果有人能帮助我或指出一个可以提供帮助的来源,我将不胜感激。

提前感谢所有帮助。

4 个答案:

答案 0 :(得分: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
            }
          ]
        }
      ]
    }
  ]

答案 1 :(得分:0)

您可能想尝试自定义ResultHandler。我想,你的CustomSet应该可行。我将进一步调查,如果我找到了什么,我会更新。

答案 2 :(得分:0)

看起来ResultHandler可以解决这个问题,但这让我编写了大量代码,留​​下了XML映射工厂的好处。此外,每个返回行调用一次处理程序的事实令我担心。

我在a message in the mybatis-user group中发现Mybatis实际上不会做我想要的事情(即使我摆脱了中间人CustomSet,看起来Mybatis看起来不会填充hashmap我需要它的方式)因此我决定采用该主题中的OP正在做的事情:获取一个列表并自己填充HashMap。这将允许我通过映射获取对象,只需少量代码,就可以填充必要的HashMap

答案 3 :(得分:0)

我曾经遇到过同样的问题。 正如@Andy Pryor建议你可以使用ResultHandler。 但正如我刚才“拆分”你的数据一样。

我的意思是将您在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那么。