【问题标题】:Native query with named parameter fails with "Not all named parameters have been set"带有命名参数的本机查询失败并显示“未设置所有命名参数”
【发布时间】:2015-05-03 23:41:20
【问题描述】:

我想执行一个简单的原生查询,但它不起作用:

@Autowired
private EntityManager em;

Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
em.setProperty("username", "test");
(int) q.getSingleResult();

为什么会出现这个异常?

org.hibernate.QueryException: Not all named parameters have been set: [username]

【问题讨论】:

  • 只是提示,为什么要对这个查询使用本机查询?您可以使用 Jpa 查询语言来做同样的事情,更喜欢 Jpa 查询有很多好处。
  • @Rafael Zeffa 我可以在没有@Entity 类的情况下使用 jpa 吗?如果是这样,您能否建议如何使用 jpa 对其进行优化?
  • 没有实体就不行,但是为什么不能为那个表映射一个@entity呢?
  • 你打电话给setProperty。应该是setParameter。另见this answer

标签: java hibernate jpa


【解决方案1】:

JPA 在本机查询中不支持命名参数,仅适用于 JPQL。您必须使用位置参数。

命名参数遵循第 4.4.1 节中定义的标识符规则。命名参数的使用适用于 Java Persistence 查询语言,并且未针对本机查询进行定义。 只有位置参数绑定可移植地用于本机查询。

所以,用这个

Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");

虽然 JPA 规范不支持原生查询中的命名参数,但某些 JPA 实现(如 Hibernate)可能支持它

原生 SQL 查询支持位置参数和命名参数

但是,这会将您的应用程序与特定的 JPA 实现结合起来,从而使其不可移植。

【讨论】:

  • 是的,但我忘记了...并在我的示例中对其进行测试。请将此答案标记为正确。
  • 我知道是一个旧线程,但 JPA 确实允许命名参数,原始问题的问题是:em.setProperty("username", "test");应该是这样的 q.setParameter("username", "test");
【解决方案2】:

经过多次尝试我发现你应该使用createNativeQuery 并且你可以使用#替换发送参数

在我的例子中

String UPDATE_lOGIN_TABLE_QUERY = "UPDATE OMFX.USER_LOGIN SET LOGOUT_TIME = SYSDATE WHERE LOGIN_ID = #loginId AND USER_ID = #userId";


Query query = em.createNativeQuery(logQuery);

            query.setParameter("userId", logDataDto.getUserId());
            query.setParameter("loginId", logDataDto.getLoginId());

            query.executeUpdate();

【讨论】:

    【解决方案3】:

    您呼叫的是setProperty,而不是setParameter。将您的代码更改为

    Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
    em.setParameter("username", "test");
    (int) q.getSingleResult();
    

    它应该可以工作。

    【讨论】:

      【解决方案4】:

      我使用 EclipseLink。此 JPA 允许使用以下方式进行本机查询:

      Query q = em.createNativeQuery("SELECT * FROM mytable where username = ?username");
      q.setParameter("username", "test");
      q.getResultList();
      

      【讨论】:

        【解决方案5】:

        使用查询中的设置参数。

        Query q = (Query) em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
        q.setParameter(1, "test");
        

        【讨论】:

        • 不,这是正确的导入。但是你应该使用整数参数。 NativeQuery 不适用于字符串参数。我编辑我的答案。
        • 顺便说一句,您可能想要还原您的编辑。它确实适用于命名参数 (... username = :username)。
        • 通常你应该在本地 SQL 查询“SELECT count(*) FROM Persons where username = :username”中使用命名参数“username”。但是原生SQL查询中不允许命名参数,使用整数参数
        • @pL4Gu33 Wihle JPA 不支持这个,一些实现支持,比如 Hibernate。这就是它适用于 OP 的原因。我已使用此信息编辑了我的答案。
        【解决方案6】:

        这是 4.3.11 版本中修复的错误 https://hibernate.atlassian.net/browse/HHH-2851

        编辑: 执行本机查询的最佳方式仍然是使用 NamedParameterJdbcTemplate 它允许您需要检索不是托管实体的结果;您可以使用RowMapper,甚至可以使用命名参数映射

        private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
        
        @Autowired
        public void setDataSource(DataSource dataSource) {
            this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
        }
        
        final List<Long> resultList = namedParameterJdbcTemplate.query(query, 
                    mapOfNamedParamters, 
                    new RowMapper<Long>() {
                @Override
                public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
                    return rs.getLong(1);
                }
            });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-29
          • 2013-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-11
          相关资源
          最近更新 更多