Java 使用带有可空外键的QueryDSL在Spring数据JPA存储库中进行筛选
我一直有这样一个问题,我无法使用querydsl对一个表进行正确的筛选,querydsl有一个可为空的外键。我将用例简化为一个非常简单的场景 假设我们有两个实体,MyEntity和TimeRangeEntity。我的实体只有一个ID和TimeRange实体的外键。TimeRangeEntity只有一个开始时间和结束时间以及一个ID。BaseEntity(这两者都是从其扩展而来)只有一个带有@ID注释的IDJava 使用带有可空外键的QueryDSL在Spring数据JPA存储库中进行筛选,java,spring,hibernate,spring-data-jpa,querydsl,Java,Spring,Hibernate,Spring Data Jpa,Querydsl,我一直有这样一个问题,我无法使用querydsl对一个表进行正确的筛选,querydsl有一个可为空的外键。我将用例简化为一个非常简单的场景 假设我们有两个实体,MyEntity和TimeRangeEntity。我的实体只有一个ID和TimeRange实体的外键。TimeRangeEntity只有一个开始时间和结束时间以及一个ID。BaseEntity(这两者都是从其扩展而来)只有一个带有@ID注释的ID @Entity @Table(name = "TEST_OBJECT") public c
@Entity
@Table(name = "TEST_OBJECT")
public class MyEntity extends BaseEntity {
@OneToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST })
private TimeRangeEntity actionTime;
public TimeRangeEntity getActionTime() {
return actionTime;
}
public void setActionTime(TimeRangeEntity actionTime) {
this.actionTime = actionTime;
}
}
@Entity
@DiscriminatorValue("static")
public class TimeRangeEntity extends BaseEntity {
@Column(name = "START_TIME")
private Instant startTime;
@Column(name = "END_TIME")
private Instant endTime;
public Instant getStartTime() {
return startTime;
}
public void setStartTime(Instant startTime) {
this.startTime = startTime;
}
public Instant getEndTime() {
return endTime;
}
public void setEndTime(Instant endTime) {
this.endTime = endTime;
}
}
我在我的存储库中构造了一个默认方法来运行findAll,并使用querydsl来构建SQL语法
@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long>, QueryDslPredicateExecutor<MyEntity> {
default Page<MyEntity> paginateFilter(PaginationInfo info, String filter){
int page = info.getOffset() > 0 ? info.getOffset() / info.getLimit() : 0;
PageRequest pageRequest = new PageRequest(page, info.getLimit(), new Sort(new Sort.Order(info.getSortDirection(), info.getSortProperty())));
return findAll(createFilterPredicate(filter, myEntity), pageRequest);
}
default Predicate createFilterPredicate(String filter, QMyEntity root){
BooleanBuilder filterBuilder = new BooleanBuilder();
filterBuilder.or(root.id.stringValue().containsIgnoreCase(filter));
filterBuilder.or(root.actionTime.startTime.isNotNull());
return filterBuilder.getValue();
}
}
看看这个,我几乎可以肯定这是由于snipper交叉连接时间\范围\实体时间范围1\其中myentity0\动作\时间\ id=timerangee1\范围id
,因为它验证实体匹配,如果范围外键为空,则无法验证实体匹配
我一直在努力实现这个条件工作,如果FK不为null,它只检查时间范围的表属性,但我找不到使用querydsl的方法。任何建议/指导/代码片段都是一流的
编辑:仅转换为直接SQL,我得到了生成的JPQL的查询(由于我将其用于实际数据,因此转换为本例):
如果FK为空,则不会按预期返回行。将此连接从交叉连接更改为左连接最终工作正常
select * from test_object left join time_range on test_object.action_time_id=time_range.id where lower(cast(test_object.id as char)) like '%1%';
这样,有没有办法指定querydsl谓词执行器的左连接?这似乎是解决我问题的办法 尝试使用规范而不是谓词
private Specification<QMyEntity> createFilterPredicate(final String filter, final QMyEntity root) {
return new Specification<QMyEntity>() {
@Nullable
@Override
public Predicate toPredicate(Root<QMyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
Join<Object, Object> actionTime = root.join("actionTime", JoinType.LEFT);
return criteriaBuilder.or(criteriaBuilder.like(criteriaBuilder.lower(root.get("id")), "%" + filter + "%"), criteriaBuilder.isNotNull(actionTime.get("startTime")));
}
};
}
专用规范createFilterPredicate(最终字符串筛选器,最终QMyEntity根){
返回新规范(){
@可空
@凌驾
公共谓词toPredicate(根根、标准查询、,
CriteriaBuilder(标准编辑器){
Join actionTime=root.Join(“actionTime”,JoinType.LEFT);
返回criteriaBuilder.or(criteriaBuilder.like(criteriaBuilder.lower(root.get(“id”)),“%”“+”filter+“%”),criteriaBuilder.isNotNull(actionTime.get(“startTime”);
}
};
}
这看起来很有希望。我现在要试一试。这是一个相当重要的改变,我一直在做的事情,但这可能是必要的。为了获得CriteriaQuery/CriteriaBuilder,我必须创建一个新接口和一个类实现来获得实体管理器。我们将看到当我艰难地完成改变时会发生什么!谢谢,这就是我需要做的!不像其他谓词方法那么干净,但我将接管clean;)
select * from test_object cross join time_range range where test_object.action_time_id=range.id and lower(cast(test_object.id as char)) like '%1%';
select * from test_object left join time_range on test_object.action_time_id=time_range.id where lower(cast(test_object.id as char)) like '%1%';
private Specification<QMyEntity> createFilterPredicate(final String filter, final QMyEntity root) {
return new Specification<QMyEntity>() {
@Nullable
@Override
public Predicate toPredicate(Root<QMyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder criteriaBuilder) {
Join<Object, Object> actionTime = root.join("actionTime", JoinType.LEFT);
return criteriaBuilder.or(criteriaBuilder.like(criteriaBuilder.lower(root.get("id")), "%" + filter + "%"), criteriaBuilder.isNotNull(actionTime.get("startTime")));
}
};
}