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 语句中创建新对象