Spring Data JPA和Exists查询

96

我正在使用Spring Data JPA(使用Hibernate作为JPA提供者),并且想要定义一个带有HQL查询的exists方法:

public interface MyEntityRepository extends CrudRepository<MyEntity, String> {

  @Query("select count(e) from MyEntity e where ...")
  public boolean existsIfBlaBla(@Param("id") String id);

}
当我运行这个查询时,我得到一个java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Boolean的错误。
HQL查询应该如何才能使其正常工作?我知道我可以简单地返回一个Long值,然后在我的Java代码中检查count > 0,但是这种解决方法不应该是必要的,对吧?

2
显然,您可以更改JPQL查询以返回布尔值...而不是返回“count(e)”,而是返回布尔表达式。 - Neil Stockton
9个回答

224

Spring Data JPA 1.11现在支持在仓库查询派生中使用exists投影。

请参阅此处的文档。

对于您的情况,以下内容将起作用:

public interface MyEntityRepository extends CrudRepository<MyEntity, String> {  
    boolean existsByFoo(String foo);
}

4
如果你能添加一个可行的例子,我很乐意点赞。 - Stefan Haberl
12
这就是Spring Data的全部意义- 您不必编写任何HQL :) - bartektartanus
3
是的,但如果你想检查一个字段上是否有值的记录 - 这绝对是简单的用例 :) 但对于更复杂的情况,我同意 - Spring Data有时不够高效。 - bartektartanus
1
无法工作。org.springframework.data.mapping.PropertyReferenceException: 找不到类型Xxx的existsByXxx属性! - Jagger
1
@AnkitSoni,结果证明,Spring Data JPA 1.11首次出现在Spring Boot 1.5中。 - Jagger
显示剩余7条评论

101

我认为你可以简单地更改查询以返回布尔值

@Query("select count(e)>0 from MyEntity e where ...")

提示: 如果您是基于主键值进行存在性检查,则 CrudRepository 已经拥有 exists(id) 方法。


1
感谢您指出exists(id)的方法,但我的where子句包含一些复杂的约束条件... - Stefan Haberl
31
count(e)>e will likely only work with certain databases (e.g. Oracle). With DB2 it does not and you will have to use select case when count(e) > 0 then true else false end from Entity e - JRA_TLL
2
在这里执行一个SQL exists查询,而不是计算行数。使用count必须完成索引中的所有行(希望如此),否则没有索引会进行表扫描。SQL exists将在遇到第一行后返回,而不是像count(*)那样找到每一行并计数。在一个10行的表中,这没有问题,在10万/百万及以上的数据量时就很重要了。 - JMDenver
基本上,检查计数某些东西比仅检查其存在要慢;在没有更好的解决方案的情况下,答案有效,但它并不是最佳选择。 - Haroldo_OK
我不知道是否有人指出这一点,对于所有Hibernate相关的事情,我看Vlad Mihalcea的工作。我刚用这个链接解决了同样的问题。 https://vladmihalcea.com/spring-data-exists-query/ 在我的情况下,我能够利用JPARepository.existsById()。 - Dave B
@JRA_TLL 在 Oracle 上不起作用。30 个赞可能会让它工作吗?但现在不行了... - VXp

25

在我的情况下,它不像以下那样工作

@Query("select count(e)>0 from MyEntity e where ...")

您可以使用以下方式将其作为布尔值返回:

@Query(value = "SELECT CASE  WHEN count(pl)> 0 THEN true ELSE false END FROM PostboxLabel pl ...")

22

现在这些事情变得更加容易了!

@Repository
public interface PageRepository extends JpaRepository<Page, UUID> {

    Boolean existsByName(String name); //Checks if there are any records by name
    Boolean existsBy(); // Checks if there are any records whatsoever

}

12
自 Spring data 1.12 版本起,您可以通过扩展 QueryByExampleExecutor 接口(JpaRepository 已经扩展了它)来使用“按示例查询”功能。
然后,您可以使用以下查询(等等):
<S extends T> boolean exists(Example<S> example);
考虑一个实体MyEntity, 该实体具有属性name,您想知道是否存在一个同名的实体,忽略大小写。那么调用此方法的代码如下:
//The ExampleMatcher is immutable and can be static I think
ExampleMatcher NAME_MATCHER = ExampleMatcher.matching()
            .withMatcher("name", GenericPropertyMatchers.ignoreCase());
Example<MyEntity> example = Example.<MyEntity>of(new MyEntity("example name"), NAME_MATCHER);
boolean exists = myEntityRepository.exists(example);

并不适用于我的情况,因为我的查询是使用HQL的。 - Stefan Haberl

3
你可以在选择查询中使用Case表达式来返回一个boolean,如下所示。
@Query("SELECT CASE WHEN count(e) > 0 THEN true ELSE false END FROM MyEntity e where e.my_column = ?1")

哪些?据我所知,它总是返回布尔值,对吧? - skwisgaar
你尝试过哪些数据库? - Sahil Chhabra

3
除了被接受的回答外,我提出另一种选择。 使用QueryDSL,创建一个谓词并使用接受谓词并返回布尔值的exists()方法。
使用QueryDSL的一个优点是你可以将该谓词用于复杂的where子句。

1

Spring Data提供了使用字段检查行是否存在的方法: 例如:boolean existsByEmployeeIdAndEmployeeName(String employeeId, String employeeName);


-7

你可以在 jpaRepository 中使用 .exists (返回布尔值)。

if(commercialRuleMsisdnRepo.exists(commercialRuleMsisdn.getRuleId())!=true){

        jsRespon.setStatusDescription("SUCCESS ADD TO DB");
    }else{
        jsRespon.setStatusCode("ID already exists is database");
    }

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