Return Map<Long, String> directly from CrudRepository.

huangapple go评论62阅读模式
英文:

Return Map<Long, String> directly from CrudRepository

问题

我需要返回具有role='ADMIN'的所有用户的idname作为Map<Long, String>,例如:

@Query("SELECT u.id, u.name FROM User u WHERE u.role = :role")
Map<Long, String> findIdAndNameByRole(String role);

但是这个调用返回了一个错误:

javax.persistence.NonUniqueResultException: query did not return a unique result

问题:是否有可能以不使用投影或其他转换的方式将CrudRepository的响应直接映射到Map<Long, String>,也许可以通过nativeQuery=true来实现?

英文:

Say I have a table users with columns id, role, name etc.

There's UserRepository defined as:

public interface UserRepository extends CrudRepository&lt;User, Long&gt; {
    ...
}

I need to return all ids and names of users with role='ADMIN' as Map&lt;Long, String&gt; e.g.:

@Query(&quot;SELECT u.id, u.name FROM User u WHERE u.role = :role&quot;)
Map&lt;Long, String&gt; findIdAndNameByRole(String role);

But this call returns an error:

> javax.persistence.NonUniqueResultException: query did not return a unique result

Question: how (if possible at all) to map the response from CrudRepository directly to Map<Long, String> without using projections or other conversions? Perhaps using nativeQuery=true somehow?

答案1

得分: 3

根据文档,存储库方法基本上只能返回单个基本值,存储库类型的单个对象(在您的情况下为User),或者其中的各种集合。

无论如何,您都必须使用某种类型的转换方法。您能详细说明为什么不能使用任何“投影或其他转换”吗?通常,对于您的业务逻辑类,最好不要直接访问存储库,而是使用中间服务类进行这些转换,因为这不是一个不常见的情况。

我能想到的唯一替代方法是在存储库接口中使用一个default方法进行转换,但这可能不起作用。

示例:

public interface UserRepository extends CrudRepository<User, Long> {
    // 普通存储库方法。不需要@Query。
    Stream<User> findByRole(String role);

    default Map<Long, String> findIdAndNameByRole(String role) {
         return findByRole(role).collect(toMap(User::getId, User::getName));
    }
}
英文:

According to the documentation repository methods basically only can single primitive values, a single objects of the repository type (User in your case) or various collections of it.

You will have to use a conversion method of some type in any case. Can you elaborate why you can't use any "projections or other conversions"? It's generally good practice for your business logic classes not to access repositories directly anyway, but use an intermediate service class that do exactly such conversions, since it's not an uncommon scenario.

The only alternative I can think of is to use a default method in the repository interface that does the conversion, but that may not work.

Example:

public interface UserRepository extends CrudRepository&lt;User, Long&gt; {
    // Normal repository method. No @Query needed.
    Stream&lt;User&gt; findByRole(String role);

    default Map&lt;Long, String&gt; findIdAndNameByRole(String role) {
         return findByRole(role).collect(toMap(User::getId, User::getName));
    }
}

答案2

得分: 0

你之所以出现错误是因为查询返回了多行数据。

要解决这个问题,你可以创建一个 Map 列表,而不是传递一个单独的 Map。

@Query("SELECT u.id AS id, u.name AS name FROM User u WHERE u.role = :role")
List<Map<String, Object>> findIdAndNameByRole(String role);

然后,要遍历这个 Map 列表,你可以创建如下方法:

public Map<Long, String> getIdAndNameMapByRole(String role) {
    List<Map<String, Object>> resultList = userRepository.findIdAndNameByRole(role);
    Map<Long, String> idAndNameMap = new HashMap<>();

    for (Map<String, Object> result : resultList) {
        Long id = (Long) result.get("id");
        String name = (String) result.get("name");
        idAndNameMap.put(id, name);
    }

    return idAndNameMap;
}
英文:

You are getting error because the query is returning multiple rows.

So to fix this, you can create a list of Map instead of passing the Map.

@Query(&quot;SELECT u.id AS id, u.name AS name FROM User u WHERE u.role = :role&quot;)
List&lt;Map&lt;String, Object&gt;&gt; findIdAndNameByRole(String role);

And for iterating this list of map, you can create a method like below:

public Map&lt;Long, String&gt; getIdAndNameMapByRole(String role) {
    List&lt;Map&lt;String, Object&gt;&gt; resultList = userRepository.findIdAndNameByRole(role);
    Map&lt;Long, String&gt; idAndNameMap = new HashMap&lt;&gt;();

    
    for (Map&lt;String, Object&gt; result : resultList) {
        Long id = (Long) result.get(&quot;id&quot;);
        String name = (String) result.get(&quot;name&quot;);
        idAndNameMap.put(id, name);
    }

    return idAndNameMap;
}

huangapple
  • 本文由 发表于 2023年6月13日 04:24:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76460087.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定