如何在Spring Data JPA中获取结果集中的列名

3

我有一个简单的过程,用于列出用户。我使用@NamedStoredProcedureQueries进行过程声明,并使用EntityManager.createNamedStoredProcedureQuery来创建StoredProcedureQuery

它可以正确返回结果,但我需要列名,以便我知道哪个值属于哪个列。

我的代码大致如下

实体类

@Entity
@NamedStoredProcedureQueries({ @NamedStoredProcedureQuery(name = 
    "sGetUserList", procedureName = "sGetUserList", parameters = { 
    @StoredProcedureParameter(mode = ParameterMode.IN, name = "user_id", type = 
    Integer.class) }) 
})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;

    private String email;

    //getters and setters
}

自定义仓库

public interface UserRepositoryCustom {
    List<?> testProc() ;
}

代码仓库

public interface UserRepository extends JpaRepository<User, Long>, 
UserRepositoryCustom{

}

仓库实现

public class UserRepositoryImpl implements UserRepositoryCustom{

    @PersistenceContext
    EntityManager em;

    public List<Object> testProc() {

        StoredProcedureQuery q = em.createNamedStoredProcedureQuery("sGetUserList");
        q.setParameter("user_id", 1);
        List<Object> res = q.getResultList();

        return res;
    }
}

我需要带有列名的结果。
4个回答

6
您可以将列名及其值存储到一个Map中,格式为: Map<'column-name', value>
Query query = entityManager.createNativeQuery("{call <<Your procedure>>}");
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> result = nativeQuery.getResultList();

这将非常有用,特别是在想在HTML中使用列名作为占位符,在运行时会被值替换的地方。

1
如何处理列名的随机顺序? - sys49152

4
这里,我为您编写了一个方法,您可以从中获取JSON,该JSON包含列和值的键值对。
@Transactional
@Component
public class CustomRepository<T> {

    @Autowired
    private EntityManager em;

    private ObjectMapper mapper = new ObjectMapper();

    public List<T> getResultOfQuery(String argQueryString,Class<T> valueType) {
        try {
            Query query = em.createNativeQuery(argQueryString);
            NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
            nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
            List<Map<String,Object>> result = nativeQuery.getResultList();
            List<T> resultList = result.stream()
                    .map(o -> {
                        try {
                            return mapper.readValue(mapper.writeValueAsString(o),valueType);
                        } catch (Exception e) {
                            ApplicationLogger.logger.error(e.getMessage(),e);
                        }
                        return null;
                    }).collect(Collectors.toList());
            return resultList;
        } catch (Exception ex) {
            ApplicationLogger.logger.error(ex.getMessage(),ex);
            throw ex;
        }
    }
}

唯一的条件是您的查询和pojo属性名称应相同。

上帝保佑你,伙计!你救了我。非常感谢! - geeekfa

1
我不确定我理解你在这里想要做什么。如果你想获取所有使用Spring数据的用户,你不应该实现UserRepository。Spring Data已经为你做了这件事。
事实上,JpaRepository已经有你需要的方法。
List<User> findAll();

你只需要调用这个方法就可以获取到所有用户的列表,无需担心列名。
只需在需要的地方注入你的仓库并调用该方法即可获取所有用户:
@Autowire
UserRepository userRepository;

List<Users> allUsers = userRepository.findAll();

编辑:如果您有特定的原因想使用存储过程,但不想自己实现UserRepository,那么可以使用Spring Data的方法来完成。您可以通过定义以下方法来实现:
public interface UserRepository extends JpaRepository<User, Long>{
   @Procedure(name = "sGetUserList")
   List<User> sGetUserList(@Param("user_id") Integer userId);

}

使用这种方法解析列名不应该有任何问题。


在这种情况下是可以的,但如果我有一些过程进行分析并给出结果,而该结果集没有任何模型,那该怎么办呢?例如,如果我编写一个过程,它给出了一天内登录次数的用户列表。它有一个计数列,我在任何地方都没有定义过。这只是一个例子,我有很多类似的分析过程。如何解决这种情况? - Nikesh Kedlaya
1
好的,这是一个更困难的情况。据我了解,如果您想要为一个未定义的实体获取列名,最好使用JDBC而不是Spring Data。在Spring Data中,您需要定义具有与预期结果集列匹配的属性的@Entities,并在其上放置@NamedStoredProcedureQueries注释来实现这一点。 - Plog
@Plog我可以用同样的方法获取表的列名吗?还是从数据库的表中检索的过程不同? - Alekya

0
为了保持列名的顺序,您可以使用LinkedHashMap构建自己的AliasedTupleSubsetResultTransformer,如下所示:

public class AliasToEntityLinkedHashMapResultTransformer extends AliasedTupleSubsetResultTransformer {

    public static final AliasToEntityLinkedHashMapResultTransformer INSTANCE = new AliasToEntityLinkedHashMapResultTransformer();

    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        LinkedHashMap result = new LinkedHashMap(tuple.length);

        for (int i = 0; i < tuple.length; i++) {
            String alias = aliases[i];
            if (alias != null) {
                result.put(alias, tuple[i]);
            }
        }
        return result;
    }

    @Override
    public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
        return false;
    }

    private Object readResolve() {
        return INSTANCE;
    }
}

并在其中使用:

nativeQuery.setResultTransformer(AliasToEntityLinkedHashMapResultTransformer.INSTANCE);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接