带输入参数的命名查询
Named query with input parameter
我正在使用 Hibernate 学习 JPA,同时也使用 Maven。我的问题是如何在命名查询中使用带有 UPDATE 和 SET 子句的输入参数?
@NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")
它给我一个参数只能在 WHERE 或 HAVING 子句中使用的错误。我参考了几篇文章,但仍然找不到合适的解决方案。
你能试试位置参数看看行不行?
@NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")
//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
您必须构建一个如下命名的查询:
Query query = getEntityManager().createNamedQuery("updateEmailAddress");
query.setParameter("email", "email@test.com");
query.setParameter("username", "emailuser");
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
来源:
在 JPA 2.0 及以下版本中,命名查询的 set 子句中不允许使用参数;只有文字。如果您使用的是 JPA 2.1,则取消此限制。
据我所知,您没有使用 JPA 2.1。因此,我将为您提供几种方法来避开此限制。
选项 1:
使用 createQuery 方法并将动态生成的字符串传递给该方法。
String queryString = generateQueryString(email, username);
entityManager.createQuery(queryString).executeUpdate();
选项 2:
更新关联的实体并合并。
List<User> result = entityManager.createQuery('select u from user u where
u.username = :username').setParameter('username', username).getResultList();
for (User user : result) {
user.setEmail(email);
entityManager.merge(user);
}
选项 3:
使用 HQL 而不是 JPQL 创建查询。我没有对此进行测试,也不推荐它,因为您落后于实体经理。
Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
q.setParameter('email', email);
q.setParameter('username', username);
q.executeUpdate();
虽然事实上在 JPA 2.1 之前这是不允许的,但您实际上可以使用它,因为提供程序会让您以这种方式提供参数(事实证明这是一件好事!)。
似乎 JPA 提供程序不符合有关此验证的规范,我认为这只是因为它没有任何意义(您可以在 2.1 中看到它现在被允许)。 "Why would me make it difficult do developers?"
我也在使用 EclipseLink 2.3.1,它工作正常。
推荐方案
只需禁用 Eclipse 的 JPQL 查询验证。
如果提供者接受它,你应该没问题,否则你需要符合规范。很简单的。代码会更简洁,并且符合最近对规范的评估。
只需转到:Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries:
和 Ignore
it
查看this article了解详情:
Conclusion
Hibernate does not follow the specification on this point but one
might guess that the new version of the JPA-spec will allow this
behavior as indicated by the draft JSR. JBoss Tools is probably
validating the query against the JPQL-grammar which is based on the
specification and is therefore showing a validation error.
这是解决方案:
End remark
After a discussion in out team we decided to keep the current
implementation despite the breach of specification. Changing the
behavior would mean string concatenation or string substitution to
build the query and the current approach is much cleaner. As we see no
indications of a shift in persistence provider or application server
at this stage we believe the gains of keeping the code are larger than
the risks at this point.
我正在使用 Hibernate 学习 JPA,同时也使用 Maven。我的问题是如何在命名查询中使用带有 UPDATE 和 SET 子句的输入参数?
@NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")
它给我一个参数只能在 WHERE 或 HAVING 子句中使用的错误。我参考了几篇文章,但仍然找不到合适的解决方案。
你能试试位置参数看看行不行?
@NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")
//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
您必须构建一个如下命名的查询:
Query query = getEntityManager().createNamedQuery("updateEmailAddress");
query.setParameter("email", "email@test.com");
query.setParameter("username", "emailuser");
int result = query.executeUpdate();
System.out.println("Rows affected: " + result);
来源:
在 JPA 2.0 及以下版本中,命名查询的 set 子句中不允许使用参数;只有文字。如果您使用的是 JPA 2.1,则取消此限制。
据我所知,您没有使用 JPA 2.1。因此,我将为您提供几种方法来避开此限制。
选项 1: 使用 createQuery 方法并将动态生成的字符串传递给该方法。
String queryString = generateQueryString(email, username);
entityManager.createQuery(queryString).executeUpdate();
选项 2: 更新关联的实体并合并。
List<User> result = entityManager.createQuery('select u from user u where
u.username = :username').setParameter('username', username).getResultList();
for (User user : result) {
user.setEmail(email);
entityManager.merge(user);
}
选项 3: 使用 HQL 而不是 JPQL 创建查询。我没有对此进行测试,也不推荐它,因为您落后于实体经理。
Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
q.setParameter('email', email);
q.setParameter('username', username);
q.executeUpdate();
虽然事实上在 JPA 2.1 之前这是不允许的,但您实际上可以使用它,因为提供程序会让您以这种方式提供参数(事实证明这是一件好事!)。
似乎 JPA 提供程序不符合有关此验证的规范,我认为这只是因为它没有任何意义(您可以在 2.1 中看到它现在被允许)。 "Why would me make it difficult do developers?"
我也在使用 EclipseLink 2.3.1,它工作正常。
推荐方案
只需禁用 Eclipse 的 JPQL 查询验证。
如果提供者接受它,你应该没问题,否则你需要符合规范。很简单的。代码会更简洁,并且符合最近对规范的评估。
只需转到:Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries:
和 Ignore
it
查看this article了解详情:
Conclusion
Hibernate does not follow the specification on this point but one might guess that the new version of the JPA-spec will allow this behavior as indicated by the draft JSR. JBoss Tools is probably validating the query against the JPQL-grammar which is based on the specification and is therefore showing a validation error.
这是解决方案:
End remark
After a discussion in out team we decided to keep the current implementation despite the breach of specification. Changing the behavior would mean string concatenation or string substitution to build the query and the current approach is much cleaner. As we see no indications of a shift in persistence provider or application server at this stage we believe the gains of keeping the code are larger than the risks at this point.