QueryDSL动态谓词

5

我需要帮助进行QueryDSL查询。我正在使用Spring Data JPA和这个库。 我的服务类:

@Service("tblActivityService")
public class TblActivityService implements AbstractService<TblActivity> {

@Resource
private TblActivityRepository tblActivityRepository;

@Override
public List<TblActivity> findAll(Predicate predicate) {
    return (List<TblActivity>) tblActivityRepository.findAll(predicate);
}
}

我有一个动态的筛选列表:

@Entity
@Table(name = "sys_filters")
public class SysFilter implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "filter_id")
private Integer filterId;

@JoinColumn(name = "user_id", referencedColumnName = "user_id")
@ManyToOne(fetch = FetchType.EAGER)
private SysUser userId;

@Size(max = 45)
@Column(name = "table_name")
private String tableName;

@Size(max = 45)
@Column(name = "column_name")
private String columnName;

@Size(max = 45)
@Column(name = "condition")
private String condition;

@Size(max = 100)
@Column(name = "value")
private String value;


// getters & setters

}

我有一个列名(例如标题)

我有一个条件(例如==,!=,> =等) - 我可以将其存储为符号或单词(equals等)。

最后,我有一个值。

问题是“如何动态生成我的服务的谓词?”表格有大约25个字段。

谓词看起来像这样:

public BooleanExpression buildFilteredResult(List<SysFilter> filters) {
    //TODO do it!
    return QTblActivity.tblActivity.title.eq("Value"); 
// I need to do it dynamically for each filter in the list
}

问题是如何通过其字符串值调用columnName。 你有什么建议吗?


提供列名作为字符串值违背了Querydsl的初衷。 Querydsl的理念是,您不需要将列名作为字符串,而是以编译安全和类型安全的方式引用它们。 - Simon
好的,我不想为所有可能的变量编写代码(那将是大量的代码)。有没有办法动态插入列名?或者还有其他实现我的需求而不使用QueryDSL的方法吗? - Vasyl Hoshovsky
3个回答

7

使用映射过滤条件到运算符可能更容易

Map<String, Operator> operators = ImmutableMap.of(
  "==", Ops.EQ, "!=", Ops.NE, ">", Ops.GT, "<", Ops.LT,
  ">=", Ops.GOE, "<=", Ops.LOE);

Expressions.predicate(operators.get(condition), 
  stringPath, Expressions.constant(filterValue));

同时确保正确地组合您的谓词

predicates.and(...)

返回一个新的谓词(predicate)并保留 predicates 不变。

也许 BooleanBuilder 是您需要的?


如果该属性是NumberPath,应该如何处理? - sendreams

1

随着Spring Data Gosling/Fowler的发布,推出了一种新的解决方案。如果您正在创建Web应用程序,可以使用querydsl Web支持来为您完成工作-它将读取get参数到谓词中,然后您可以从控制器使用此谓词-无需手动执行此操作- 您可以根据所需的特定数据类型或特定实体字段的搜索条件(相等、类似于...)自定义存储库。 在此处查看文档


0

我找到了解决方案:

public BooleanExpression buildFilteredResult(List<SysFilter> filters) {
    //TODO do it!

    QTblActivity qTblActivity = QTblActivity.tblActivity;
    BooleanExpression expression = qTblActivity.recordState;

    for (SysFilter filter : filters) {
        StringPath stringPath = new StringPath(qTblActivity, filter.getColumnName());
        switch (filter.getCondition()) {
            case "==":
                expression.and(stringPath.eq(filter.getValue()));
                break;
            case "!=":
                expression.and(stringPath.ne(filter.getValue()));
                break;
            case ">":
                expression.and(stringPath.gt(filter.getValue()));
                break;
            case "<":
                expression.and(stringPath.lt(filter.getValue()));
                break;
            case ">=":
                expression.and(stringPath.goe(filter.getValue()));
                break;
            case "<=":
                expression.and(stringPath.loe(filter.getValue()));
                break;
            default:
                break;
        }
    }

    return expression;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接