Spring Data JPA无法使用复杂表达式返回正确的结果

时间:2017-02-10 10:09:09

标签: java spring jpa spring-data spring-data-jpa

我尝试为某个实体实现过滤器。 据我所知,Spring不支持可选参数,所以当没有设置过滤器时,我检查空字符串,当设置参数时我想匹配 contains 不区分大小写

目前,没有产品链接到数据库中的角色,因此p.role始终为空。 这意味着表达式(lower(p.role.name) like concat('%', lower(:role), '%'))的第二部分永远不会为真,从而产生一个空集。 但第一部分(:role = '')应该是真的,所以我希望得到 ALL 数据。 但由于某些原因,它在这种特殊情况下无效。

ProductRepository.java

@RepositoryRestResource(collectionResourceRel = "product", path = "/product")
public interface ProductRepository extends JpaRepository<Product, Long> {
    @RestResource(path="filter", rel="filter")
    @Query("select p from Product p where"
        + "(:vendor = '' or lower(p.vendor.name) like concat('%', lower(:vendor), '%'))"
        + "and"
        + "(:role = '' or lower(p.role.name) like concat('%', lower(:role), '%'))"
    Page<Product> filterProduct(@Param("role") String role, Pageable pageable);
}

Product.java

@Entity
public class Product {
    @ManyToOne
    @JoinColumn(name = "role_id", referencedColumnName = "id")
    private Role role;

    @ManyToOne
    @JoinColumn(name = "vendor_id", referencedColumnName = "id")
    private Vendor vendor;
}

Role.java

@Entity
public class Role {
    private Long id;
    private String name;
}

Vendor.java

@Entity
public class Vendor {
    private Long id;
    private String name;

我的测试

为了进行测试,我将表达式的第二部分替换为始终为true或false的语句(1=11=2)。

ProductRepository.java

@RepositoryRestResource(collectionResourceRel = "product", path = "/product")
public interface ProductRepository extends JpaRepository<Product, Long> {
    @RestResource(path="filter", rel="filter")
    @Query("select p from Product p where"
        + "(:role = '' or 1=2)"
    Page<Product> filterProduct(@Param("role") String role, Pageable pageable);
}

案例1=1

如果我提供role参数并不重要,我总是会得到所有产品。

案例1=2

如果我没有提供role参数(例如http://localhost/product/search/filter?role=),我会收到所有产品,因为:role = ''评估为true

如果我确实提供了role参数(例如http://localhost/product/search/filter?role=foo),我会得到一个空集,因为没有名称为#foo&f 39的角色。存在。

我认为可能是因为p.role为空,尝试匹配p.role.name会导致错误,但没有错误消息,我也尝试在表达式中包含p.role is not null and ...但是没有变化。

摘要

  • :role = ''单独按预期工作。
  • :role = ''结合简单的表达方式。
  • :role = ''结合我想要的表达工作。

1 个答案:

答案 0 :(得分:1)

您无法使用点表示法直接访问关联的实体列。使用别名声明连接以访问:

@RestResource(path="filter", rel="filter")
@Query("select p from Product p LEFT JOIN p.role r LEFT JOIN p.vendor v where"
    + "(:vendor = '' or lower(v.name) like concat('%', lower(:vendor), '%'))"
    + "and"
    + "(:role = '' or lower(r.name) like concat('%', lower(:role), '%'))")
Page<Product> filterProduct(@Param("vendor") String vendor, @Param("role") String role);