简体   繁体   English

Mybatis-从SELECT返回包含Hashmap的对象

[英]Mybatis - Returning Object containing Hashmap from SELECT

I am working with Mybatis-3, and I have the following situation: 我正在使用Mybatis-3,并且遇到以下情况:

I have Class - User which looks as follows: 我有类-用户,如下所示:

public class User extends GeneralDto {

    private String userId;
    private String email;
    private String firstName;
    private String lastName;
    private long creationTimestamp;
    private long updateTimestamp;
    private List<String> tags;
    private HashMap<String, String> attributes;
    private HashMap<String, String> accounts;

    get and set to all + equals + hashcode.
}

The two hashmaps contain unknown keys and values of the type String (and they are making me a lot of trouble). 这两个哈希图包含未知的键和String类型的值(这使我很麻烦)。

I have already mapped this Class into tables using insert method. 我已经使用插入方法将此类映射到表中。 and it is mapped OK to the following tables scheme: 并将其映射到以下表方案:

User (userIdentity, userId, email, firstName, lastName, creationTimestamp, updateTimestamp)

UserAttribute (userIdentity, attributeName, attributeValue, creationTimestamp, updateTimestamp)

UserTag (userIdentity, tagName, creationTimestamp, updateTimestamp)

UserAccount (userIdentity, accountIdentity, role, creationTimestamp, updateTimestamp)

I need to create a GET method. 我需要创建一个GET方法。 The method receives UserKey object which contains the userId which is the key of a user. 该方法接收UserKey对象,该对象包含作为用户密钥的userId。 and returns an instance of the User Class. 并返回用户类的实例。

This is the SELECT statement which joins all tables and gets the relevant data from each: 这是SELECT语句,它连接所有表并从每个表中获取相关数据:

<select id="getUser" parameterType="com.intel.aa.iot.mybatis.UserResultHandler" resultMap="userResultMap" resultOrdered="true">
    SELECT
        U.userId as userId,
        U.email as email,
        U.firstName as firstName,
        U.lastName as lastName,
        U.creationTimestamp as creationTimestamp,
        U.updateTimestamp as updateTimestamp,
        UT.tagName as tagName,
        UAT.attributeName as attributeName,
        UAT.attributeValue as attributeValue,
        A.accountId as accountId,
        UAC.role as role
    FROM User U
        LEFT OUTER JOIN UserTag UT ON U.userIdentity = UT.userIdentity
        LEFT OUTER JOIN UserAttribute UAT ON U.userIdentity = UAT.userIdentity
        LEFT OUTER JOIN UserAccount UAC ON U.userIdentity = UAC.userIdentity
        LEFT OUTER JOIN ACCOUNTS A ON UAC.accountIdentity = A.accountIdentity
    WHERE U.userId = #{userKey.userId}

This query might return more than one row, because of the joins, but all rows are of the given userId. 由于存在联接,此查询可能返回多个行,但是所有行都是给定的userId。

My question is how do i map this into one result which is an instance of the User Class. 我的问题是如何将其映射到作为用户类实例的一个结果中。 I tried using result map but encountered a problem with mapping the hashmap. 我尝试使用结果图,但在映射哈希图时遇到问题。 Then I tried using ResultHandler - returning class called UserProperties which contains each hashmap as two lists (see code below), but unfortunately it didn't work as well - only one value for each list is saved eventually. 然后,我尝试使用ResultHandler-返回名为UserProperties的类,该类将每个哈希图包含为两个列表(请参见下面的代码),但不幸的是,它也无法正常工作-最终仅为每个列表保存了一个值。

The UserProperties class: UserProperties类:

public static class UserProperties {
    private User user;
    private List<String> attributeNames;
    private List<String> attributeValues;
    private List<String> accountIds;
    private List<String> accountRoles;

    get and set to all
}

ResultMap: 的ResultMap:

<resultMap id="userResultMap" type="com.intel.aa.iot.mybatis.UserMapper$UserProperties">
    <association property="user" javaType="com.intel.aa.iot.dto.User">
        <id property="userId" column="userId"/>
        <result property="email" column="email"/>
        <result property="firstName" column="firstName"/>
        <result property="lastName" column="lastName"/>
        <result property="creationTimestamp" column="creationTimestamp"/>
        <result property="updateTimestamp" column="updateTimestamp"/>
        <collection property="tags" javaType="java.util.ArrayList" column="tagName" ofType="java.lang.String"/>
    </association>
    <collection property="attributeNames"  javaType="java.util.ArrayList" column="attributeName" ofType="java.lang.String"/>
    <collection property="attributeValues" javaType="java.util.ArrayList" column="attributeValue" ofType="java.lang.String"/>
    <collection property="accountIds" javaType="java.util.ArrayList" column="accountId" ofType="java.lang.String"/>
    <collection property="accountRoles" javaType="java.util.ArrayList" column="role" ofType="java.lang.String"/>
</resultMap>

What are my ways for dealing with these Hasmaps? 我如何处理这些Hasmap?

Thanks! 谢谢!

I've had this same issue myself over the last couple of years, but I've not found an ideal solution yet. 在过去的几年中,我本人也遇到过同样的问题,但是我还没有找到理想的解决方案。 Ultimately the problem is that mybatis does not allow you to specify the key of a hashmap - it uses the result property name as the key. 最终,问题在于mybatis不允许您指定哈希图的键-它使用结果属性名称作为键。

The two approaches I've taken to work around this are far from perfect, but I'll outline them here in case they're useful for you: 为解决此问题,我采取的两种方法远非完美,但如果它们对您有用,我将在此处概述它们:

  1. Use a result handler. 使用结果处理程序。 I see you say you've tried this but are only getting the first value - any chance you could share your code? 我看到您说您已经尝试过此操作,但仅获得了第一个价值-您是否有机会共享您的代码? The result handler gets called once per row returned in the query, so you don't want to create a new object each time. 查询中返回的每一行都会调用一次结果处理程序,因此您不想每次都创建一个新对象。 You want to create an object only if you don't already have one that matches the ID in this row, and then iteratively build it up based on the following rows. 仅当您没有与该行中的ID匹配的对象时,才想创建一个对象,然后根据以下各行迭代地构建它。

  2. Build the names and values as a list of hashmaps and then use a select interceptor (mybatis plugin) to call a method inside the object to construct your real hashmaps. 将名称和值构建为哈希表列表,然后使用选择拦截器(mybatis插件)调用对象内部的方法来构造您的真实哈希表。 To do this, in your result map you need to specify your name and value results under a association of type hashmap. 为此,在结果图中,您需要在类型hashmap的关联下指定名称和值结果。 Then Mybatis will turn this into a list that looks like: 然后,Mybatis将把它变成一个看起来像这样的列表:

    [List [Hashmap {"attributeName"=name1,"attributeValue"=value1}], [Hashmap {"attributeName"=name2,"attributeValue"=value2}]] [列表[Hashmap {“ attributeName” = name1,“ attributeValue” = value1}],[Hashmap {“ attributeName” = name2,“ attributeValue” = value2}]

Then you can call a method in the interceptor that iterates over this hashmap to build the hashmap you want. 然后,您可以在拦截器中调用在该哈希表上进行迭代的方法,以构建所需的哈希表。

Neither solution is pretty. 两种解决方案都不是很漂亮。 The first solution loses the elegance of result maps, and the second solution dirties your domain object. 第一个解决方案失去了结果图的优雅,第二个解决方案弄脏了您的域对象。 But if you are interested in further details let me know and I will add some code examples. 但是,如果您对更多详细信息感兴趣,请告诉我,我将添加一些代码示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM