有没有办法在 Spring Data @Query 注释值中使用常量?

Posted

技术标签:

【中文标题】有没有办法在 Spring Data @Query 注释值中使用常量?【英文标题】:Is there a way to use constants inside Spring Data @Query annotation value? 【发布时间】:2013-08-26 12:20:47 【问题描述】:

我不想硬编码常量值,我宁愿通过引用变量来指定它们。

例如,而不是编写下一个查询:

@Query(value = "SELECT u FROM UserModel u WHERE u.status = 1")

..我想提取硬编码值 '1' 并编写如下内容:

@Query(value = "SELECT u FROM UserModel u WHERE u.status = UserModel.STATUS_ACTIVE")  //doesn't compile

有没有办法像第二个例子那样在 spring-data 查询中指定常量?

【问题讨论】:

【参考方案1】:

你必须像这样使用完全限定的类名:

@Query("SELECT u FROM UserModel u WHERE u.status = com.example.package.UserModel.STATUS_ACTIVE")

不过,它的坏处是 IDE 不会将其识别为对 UserModel 类的使用。唯一的好处是您可以将值保存在一个地方,这在大多数情况下就足够了。 这已在IntelliJ IDEA 2017.1 中解决。我不知道其他 IDE。

【讨论】:

这会引发“com 未定义”的异常 .. 至少对我而言 您是否为您的目的应用了完全限定的包名称?我的意思是你必须用它的完全限定名称指向正确的、现有的类。 是的,我做到了。我解决了传递枚举值进行比较的问题。不优雅,但工作 它适用于我,具有完全限定的名称,但正在比较的字段在实体中定义为 @Enumerated(EnumType.STRING)【参考方案2】:

我建议在实体上创建一个 Enum 和该枚举的字段。

public enum UserModelStatus
     ACTIVE, INACTIVE


public UserModel

    /* Other fields ommitted */

    @Enumerated(EnumType.STRING)
    private UserModelStatus status;

    /* Get/Set Method */

然后创建你的存储库方法:

@Repository
public interface UserModelRepository extends JpaRepository<UserModel, Long>

    public List<UserModel> findByStatus(UserModelStatus status);


使用 Spring Data,您甚至不需要编写 JPQL,只需调用如下方法:

   @Autowired
   UserModelRepository userModelRepository;

   public void someMethod()
       List<UserModel> userModels = userModelRepository.findByStatus(UserModelStatus.ACTIVE);
   

【讨论】:

如何轻松否定 findByStatus(UserModelStatus 状态)?我的意思是获取 UserModelStatus 为 not 状态的所有 userModel? findByStatusNot(UserModelStatus 状态) 这显示了spring数据的全部威力。坚持简单查询,不用自己写sql。【参考方案3】:

如下使用:

在repository界面,定义一个常量如下:

public static final String USER_QUERY = "SELECT u FROM UserModel u WHERE u.status = " + UserModel.STATUS_ACTIVE;

现在你可以使用

@Query(value=USER_QUERY)

【讨论】:

【参考方案4】:

我已经设法通过 SpEL T() 运算符在查询中使用类 String 常量,这使您可以访问给定类的静态方法和常量。对于字符串,我必须用单引号 (') 包裹表达式,您可能也需要它(如果发生 QuerySyntaxException)。

试试这样的,

@Query("SELECT u FROM ##entityName u " +
       "WHERE u.status = #T(fully.qualified.path.UserModel).STATUS_ACTIVE")

注意:如果您使用 UserModel 而不是 ##entityName,它会以某种方式不起作用。

在文档中简要提及,请参阅:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions-beandef-xml-based

不知道什么时候支持,我有spring-data-jpa 1.4.3,spring-framework 3.2.17

【讨论】:

如果你想在原生查询中使用参数化语句,你可以使用SELECT columns FROM table_name WHERE column_name = ?#T(fully.qualified.path.ClassName).STATIC_CONSTANT_VARIABLE(添加??#T(...)。我需要WHERE column_name NOT IN (?#T(namespace.ClassName).STRING_COLLECTION_VARIABLE),而没有?,它没有被参数化,所以没有达到预期的效果。【参考方案5】:

对于标准解决方案,这个问题的答案似乎是“否”。

一些 JPA 实现可能有自己的解决方案,但休眠对于一个似乎不支持,也不支持此处其他答案建议的任何方法。

【讨论】:

【参考方案6】:

当您想直接在 @Query 注释中使用常量时,您可以编写如下内容:

@Query("SELECT u FROM UserModel u WHERE u.status = " + UserModel.STATUS_ACTIVE)

【讨论】:

这将返回一个错误,指出属性值必须是常量。 我就是这么说的。这个答案是关于在 @Query 注释中使用常量。 是的,但是 CONSTANT + CONSTANT 不再是常数了:) 因此出现错误。 这对我有用。如果您需要一个字符串,请不要忘记在查询中将其用单引号 ' 括起来。 The value for annotation attribute Query.value must be a constant expression【参考方案7】:

是的,这是一种更优雅的方式,而且它也易于阅读。例如:

@Query("SELECT xyz.id FROM XYZ AS xyz WHERE xyz.status = " + Status.OPEN + " AND xyz.active=1")

这里,Status 是一个包含静态常量的简单类:

public class Status 
    public static final int OPEN = 1;

【讨论】:

错了。您不能在这些表达式中放置常量。 Java 错误:The value for annotation attribute Query.value must be a constant expression @gene b。这在我的项目中有效,我在这个 SO 答案中确实复制了它。我的 Spring 版本是 2.3.4,如果这很重要的话。我不是这样写这个例子的。

以上是关于有没有办法在 Spring Data @Query 注释值中使用常量?的主要内容,如果未能解决你的问题,请参考以下文章

spring-data-jpa 的@Query注解的使用

spring-data-jpa 存储库在 Query 中使用 Collection 作为 @Param

spring data jpa @Query 枚举类型不返回数据

Spring Data JPA 常用注解 @Query@NamedQuery

Spring Data JPA 中使用Update Query更新实体类问题

带有分页的 Spring Data 和 Native Query