java Mybatis 3.0.5 嵌套集合映射示例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7663585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:54:06  来源:igfitidea点击:

Mybatis 3.0.5 nested collection mapping Example

javacollectionsmappingpersistencemybatis

提问by alokoko

I am investigating the mapping facilities of MyBatis 3.0.5. The database is H2 (1.3.160) in running embedded mode. With the help of the user manual, I got the straightforward parts working. But I am having a hard time mapping a Setthat uses a HashMapas the backing storage.

我正在研究 MyBatis 3.0.5 的映射工具。数据库是运行嵌入模式的 H2 (1.3.160)。在用户手册的帮助下,我得到了简单的部分。但是我很难映射Set使用 aHashMap作为后备存储的 a 。

Here's the Java code for the custom collection that has the custom set as field (simplified for brevity)

这是具有自定义设置为字段的自定义集合的 Java 代码(为简洁起见进行了简化)

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

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

    // other stuff  
}

Here's the CustomSetcode (again, simplified)

这是CustomSet代码(再次简化)

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

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

    // other stuff  
}

Here's the mapping interface:

映射界面如下:

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

This is the code that does the call into the Mybatis framework:

这是调用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(); 
} 

Here's what I could come up with the mapping XML so far:

到目前为止,这是我可以想出的映射 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>  

Through various iterations, I got "too many results" error, some other error or nothing (null is returned from the mapper call) but never the result I need. The SQL code works fine by itself and if I ask for a List with a straightforward select statement, I get the rows and the ArrayList back. The problem I am having is having the nested collection objects populated properly.

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

I have read the manual many times, searched for examples but I could not come up with the correct mapping XML for this purpose. I would appreciate if anyone can help me or point me to a source that can help.

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

Thanks in advance for all the help.

在此先感谢您的帮助。

回答by Sameer Kazi

This is my working example:

这是我的工作示例:

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

This is my query

这是我的查询

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

And output is:

输出是:

 [
    {
      "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
            }
          ]
        }
      ]
    }
  ]

回答by Andy

You may want to try a custom ResultHandler. I think though, your CustomSet should work. I'm going to investigate further, I will update if I find something.

您可能想尝试自定义ResultHandler。我认为,您的 CustomSet 应该可以工作。我会进一步调查,如果我发现了什么我会更新。

回答by alokoko

It looks like ResultHandlermay do the trick, but that leaves me writing a lot of code, leaving the benefits of the XML mapping factory. Also the fact that the handler will be called once per returned row is worrying me.

看起来ResultHandler可能会奏效,但这让我编写了大量代码,而留下了 XML 映射工厂的好处。此外,每个返回的行都会调用一次处理程序这一事实也让我感到担忧。

I found out in a message in the mybatis-user groupthat Mybatis will not actually do what I want (even if I get rid of the intermediary CustomSet, it does not look like Mybatis will be able to populate the hashmap the way I need it) so I have decided to go with what the OP in that topic is doing: Getting back a list and populating the HashMapmyself. This will allow me to get the objects through the mapping and with little amount of code, have the necessary HashMappopulated.

在 mybatis-user 组的一条消息中发现,Mybatis 实际上不会做我想做的事情(即使我摆脱了中介CustomSet,看起来 Mybatis 也无法按照我需要的方式填充哈希图)所以我决定采用该主题中的 OP 正在做的事情:取回列表并填充HashMap我自己。这将允许我通过映射获取对象,并用少量代码HashMap填充必要的内容。

回答by Dmitry Dyokin

i had the same problem once. As @Andy Pryor suggests you can use ResultHandler. But as i did just 'split' your data.

我曾经遇到过同样的问题。正如@Andy Pryor 建议的那样,您可以使用ResultHandler. 但正如我所做的那样,只是“拆分”了您的数据。

I mean move your data that is going to be in a Mapto another class. And then associate your Setwith this new class.

我的意思是将您的数据移动Map到另一个类中。然后将您的Set与这个新类相关联。

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

Note, here com.example.NewCustomItemis that new class. You just need to write one more mapper for this class and it works.

请注意,这com.example.NewCustomItem是新课程。你只需要为这个类再写一个映射器就可以了。

But if your really need to have a Mapuse ResultHandlerthen.

但如果你真的需要Map使用的ResultHandler话。