英文:
Return Map<Long, String> directly from CrudRepository
问题
我需要返回具有role='ADMIN'
的所有用户的id
和name
作为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<User, Long> {
...
}
I need to return all ids and names of users with role='ADMIN' as Map<Long, String>
e.g.:
@Query("SELECT u.id, u.name FROM User u WHERE u.role = :role")
Map<Long, String> 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<User, Long> {
// Normal repository method. No @Query needed.
Stream<User> findByRole(String role);
default Map<Long, String> 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("SELECT u.id AS id, u.name AS name FROM User u WHERE u.role = :role")
List<Map<String, Object>> findIdAndNameByRole(String role);
And for iterating this list of map, you can create a method like below:
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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论