Criteria Builder 和 Jquery DataTables - 自定义查询

Posted

技术标签:

【中文标题】Criteria Builder 和 Jquery DataTables - 自定义查询【英文标题】:Criteria Builder and Jquery DataTables - Custom query 【发布时间】:2021-10-02 16:14:56 【问题描述】:

我将 jquery 数据表与 Spring JPA 一起使用。 我想创建一个自定义查询,以便我的 Datatable 将根据 ManyToOne 相关对象的 id 显示项目列表。

PS。我显然已经为这些 DTO 声明了 Repositories、Mapper 和 Entities,我只是避免编写所有类,因为我发现它没用。

public class SezioniDTO 
    private static final long serialVersionUID = 1L;

    private long id;

    private LocalDate sezDtaggiornamento;


    private Comune Comune;




public class Comune 

    private static final long serialVersionUID = 1L;    

    private long id;

    private String comCap;

    private String comCodbelfiore;

    private String comCodcomune;







这些是我的类(我使用 mapstruct 从实体映射 dto)。 我如何在我的存储库和服务中使用标准构建器来根据 Comunes id 搜索 Sezionis?

我是 QueryDSL 和规范的新手,我只想获得这样的东西:

  @Query("Select * from Sezioni s WHERE s.id_Comune = :id", native="true")
   public DataTablesOutput <Object> findByField (@Param(value="id", input);

这是当前的服务实现

@Service
public class SezioniServiceImpl implements SezioniService

    @Autowired
    SezioniRepository repo;
    @Autowired
    SezioniMapper mapper;
    
    @Autowired
    SezioniSpecifications sezSpec;
    
    @Override
    public List<SezioniDTO> findAll() 
        return repo.findAll().stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
                .collect(Collectors.toList());
    
    
    @Override
    public List<SezioniDTO> findByIdComune(Long idcom)
        return repo.findSezionibyIdComune(idcom).stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
                .collect(Collectors.toList());
    

    @Override
    public SezioniDTO save(SezioniDTO entity) 
        return null;
        
    

    @Override
    public Optional<SezioniDTO> findById(Long id) 
        // TODO Auto-generated method stub
        return null;
    

    @Override
    public void delete(SezioniDTO entity) 
        // TODO Auto-generated method stub
        
    

    @Override
    public void deleteById(Long id) 
        // TODO Auto-generated method stub
        
    

    @Override
    public long count() 
        // TODO Auto-generated method stub
        return 0;
    

    @Override
    public DataTablesOutput<SezioniDTO> getSezioniTable(@Valid DataTablesInput input) 
        return repo.findAll(input, null, null, a -> mapper.entityToDto(a, new CycleAvoidingMappingContext()) );
    

    


以及 SezioniDTO 的当前存储库

@Repository
public interface SezioniRepository extends JpaRepository<Sezione,Long>, JpaSpecificationExecutor<Sezione>, DataTablesRepository<Sezione,Long> 

    @Query(value = "SELECT * FROM db.sezione WHERE sez_com_prg = :id  ORDER BY sez_numsezione", nativeQuery = true)
    public List <Sezione> findSezionibyIdCom(@Param(value = "id") Long id);

    


Sezione 是当前实体。如您所见,它 extends 和 DataTablesOutput 仅适用于 Specifications,我根本不了解。 我只是想创建一个类似于我在 repo 中的公共 List 的方法,但使用 DataTablesOutput 返回。

【问题讨论】:

【参考方案1】:
    定义实体:

    @Entity
    public class Sezioni 
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private LocalDate sezDtaggiornamento;
    
        @OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name = "comune_id")
        private Comune Comune;
    
        // getters & setter are omitted
    


    @Entity
    public class Comune 
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String comCap;
        private String comCodbelfiore;
        private String comCodcomune;
    
        // getters & setter are omitted
    

    定义存储库

    @Repository
    public interface SezioniRepository extends JpaRepository<Sezioni, Long> 
    
        @Query("select s from Sezioni s where s.Comune.id = :id")
        List<Sezioni> findByComuneId(Long id);
    
    使用(测试中)

    @DataJpaTest
    class SezioniRepositoryTest 
        @Autowired
        SezioniRepository sezioniRepository;
    
        @BeforeEach
        void setUp() 
            Comune comune = new Comune();
            comune.setComCap("cap42");
            comune.setComCodcomune("cod43");
    
            Sezioni sezioni = new Sezioni();
            sezioni.setComune(comune);
            sezioni.setSezDtaggiornamento(LocalDate.of(1970, 1, 1));
    
            sezioniRepository.save(sezioni);
        
    
        @Test
        void test() 
            List<Sezioni> sezionis = sezioniRepository.findByComuneId(1L);
            assertEquals(1, sezionis.size());
            assertEquals("cap42",sezionis.get(0).getComune().getComCap());
        
    

    接下来,您可以使用 MapStruct 将实体映射到 DTO(如果您希望在 API 上公开 DTO)

【讨论】:

谢谢迈克尔。无论如何,我故意从问题中省略了实体、存储库和映射器,但我明白,如果不提及它,人们可能会认为我没有声明它们。我需要了解的是别的东西,我将 Spring 与 jquery 数据表一起使用,我根本不明白 Criteria Builder 和 QueryDSL 是如何工作的【参考方案2】:

Criteria Builder 的优势在于根据您的业务登录需求动态构建查询

考虑下一个例子:

    @Service
public class SezioniQuery 

    @PersistenceContext
    private EntityManager entityManager;

    List<Sezioni> select(TriFunction<CriteriaBuilder, Root<Sezioni>, CriteriaQuery<Sezioni>, CriteriaQuery<Sezioni>> builder) 
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Sezioni> query = criteriaBuilder.createQuery(Sezioni.class);
        // SQL FROM clause
        Root<Sezioni> from = query.from(Sezioni.class);
        // SQL SELECT clause
        CriteriaQuery<Sezioni> select = query.select(from);

        // build WHERE somewhere later
        CriteriaQuery<Sezioni> apply = builder.apply(criteriaBuilder, from, query);

        // execute
        TypedQuery<Sezioni> typedQuery = entityManager.createQuery(apply);
        return typedQuery.getResultList();
    

^^ 这里我们定义样板。

接下来我们可以重用它来构建不同的查询:

    // @BeforeEach void setUp() ... omitted see prev. answer

    @Test
    void testEqual() 
        Long id = 1L;
        List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
                // WHERE id=1  
                query.where(cb.equal(from.get("id"), id)));

        assertEquals(1, sezionis.size());
        assertEquals("cap42",sezionis.get(0).getComune().getComCap());
    

    @Test
    void testGreater() 
        List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
                // WHERE id > 0
                query.where(cb.gt(from.get("id"), 0)));

        assertEquals(1, sezionis.size());
        assertEquals("cap42",sezionis.get(0).getComune().getComCap());
    

因此,使用 CriteriaBuilder 您可以动态构建查询,但这需要更多代码,非类型安全代码。

而 JpaRepository 扩展是类型安全但非动态的

【讨论】:

以上是关于Criteria Builder 和 Jquery DataTables - 自定义查询的主要内容,如果未能解决你的问题,请参考以下文章

Criteria Builder 在 Select 语句中创建新对象

如何将distinct应用于特定列并从JPA中的表中获取所有值(Criteria Builder)

JPA Criteria Query distinct

jquery query builder只适合单表查询吗

JQUERY相关

在java中Criteria 的具体使用方法