【问题标题】:Dynamic where JPA Spring BootJPA Spring Boot 动态
【发布时间】:2019-08-06 22:36:56
【问题描述】:

我的 Spring Boot 应用程序中有一个 Table 和 Pojo,如下所示。

@Entity
@Table(name = "attendance_summary")
public class AttendanceSummary implements Serializable {

  @Id
  @SequenceGenerator(name = "attendance_summary_id_seq",
    sequenceName = "attendance_summary_id_seq",
    allocationSize = 1)
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
    generator = "attendance_summary_id_seq")
  @Column(name = "id", updatable = false)
  public Integer id;

  @Column(name = "emp_id", nullable = false)
  public Integer empId;

  @Column(name = "designation_id")
  public Integer designationId;

  @Column(name = "designation_category_id")
  public Integer designationCategoryId;

  @Column(name = "department_id")
  public Integer departmentId;

  ......
}

现在我想为这些字段提供动态输入。意味着用户可能会选择 empIds、designationIds.... 或它们的任何组合,甚至没有它们的列表。 如果他们没有选择任何字段,我需要从数据库中的表中返回所有行。

但是在 jpa 中,当我们在存储库中编写方法时,我们必须指定字段名称,例如

public interface AttendanceSummaryRepository extends JpaRepository<Integer,AttendanceSummary>{
     List<AttendanceSummary> findByEmpIdAndDesignationId....(List<Integer> empIdList,List<Integer> designationIdList ... );
}

这意味着如果这些参数中的任何一个为空,我将收到错误或异常,因此我会丢失一些数据。

在 PHP 或类似的其他语言中,我可以检查所需过滤器的值,并在查询中动态添加 where 子句。

query= "Select * from attendance_summary where ";
if(empIdList != null)
    query = query + " emp_id in empIdList "
if(designationIdList != null)
    query = query + " designation_id in designationIdList "
 .....
 //You get the idea. 

有没有办法用 jpaDataMethods 做到这一点,如果是的话怎么做。非常感谢任何详细的解释/资源链接。

抱歉英语不好,如果我不能正确解释我的问题。

【问题讨论】:

    标签: java spring spring-boot jpa


    【解决方案1】:

    看看Criteria API。它允许您创建动态查询。

    在您的示例中,类似的方法可能会起作用:

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<AttendanceSummary> query = cb.createQuery(AttendanceSummary.class);
    Root<AttendanceSummary> root = query.from(AttendanceSummary.class);
    
    List<Predicate> predList = new ArrayList<>();
    if (empIdList != null) {
        predList.add(root.get('empId').in(empIdList));
    }
    if (designationIdList != null) {
        predList.add(root.get('designationId').in(designationIdList));
    }
    // ... You get the idea.
    
    Predicate[] predicates = new Predicate[predList.size()];
    predList.toArray(predicates);
    
    query.where(predicates);
    
    return entityManager.createQuery(query).getResultList();
    

    【讨论】:

    • 对不起,我对弹簧靴的经验不多。什么是实体经理?看起来你在这里注入它来使用它。您能否指出一些资源,以便我了解更多信息?
    • 实体管理器能够访问您的实体,例如 AttendanceSummary,并可以为您创建 SQL 查询。 This 教你如何用spring注入实体管理器。
    • 我认为我在使用实体管理器时遇到了一些问题。我按照本指南创建了存储库及其相应的实现。 baeldung.com/spring-data-criteria-queries [link]我使用上述逻辑来构建我的查询。可悲的是,我的代码在 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 行上得到了一个空指针。我打开调试,看到我的 entityManager 为空。检查问题并通知您
    【解决方案2】:

    您可以通过使用@Query 注释来实现这一点。详情请参考springguide

    @Query(value = "from attendance_summary where (emp_id in (?1) or ?1 is null) and (designation_id in (?2) or ?2 is null)" )
    

    查询详情:

    SELECT * #implicit so removed
    FROM   attendance_summary 
    WHERE  ( emp_id IN (?1) #true when IDs are not null, thus apply filter
              OR ?1 IS NULL #true when user input null, return all rows ) 
           AND ( designation_id IN (?2) #true when IDs are not null, thus apply filter
                  OR ?2 IS NULL #true user input null, return all rows) 
    

    Example Project 在 github 上使用 spring-boot、jpa 和 h2。寻找SchoolController & SchoolRepo 类,应用相同的逻辑,端点\school 将过滤输入ID 的结果,\allschool 将返回所有内容,因为输入为空。

    【讨论】:

    • 例如,我在这里只列出了 2/3 个字段。实际上还有更多的领域。因此,如果我这样做,我必须处理大量案例(因为用户可以选择任意数量的字段进行搜索。例如:他们选择了 emp_id 和 designation_id 但没有选择部门 id。或者部门 ID 和 designation_id 而不是任何其他。)我还被告知@Query 中的值必须是静态的。所以我不能根据输入链接逻辑。是否有更清洁的方法来做到这一点?
    • 我更改了查询以达到所需的结果,因此您不必进行多个方法签名。
    • db 字段值永远不会为空。如果任何字段的用户输入为空,我将不得不将其从搜索参数中排除。所以这个查询不起作用。
    • 您没有尝试解决方案,也没有密切关注查询,我不是将数据库字段比较为空,而是输入本身。为查询添加了解释,因此您将了解它如何处理 null 过滤器
    • 我试过查询。得到这个异常原因:org.postgresql.util.PSQLException: ERROR: syntax error at or near ")"
    猜你喜欢
    • 2018-07-22
    • 1970-01-01
    • 2019-12-02
    • 2019-07-16
    • 2017-09-17
    • 2018-07-10
    • 2021-04-02
    • 2017-07-04
    • 2020-09-12
    相关资源
    最近更新 更多