我有以下实体:
@Entity
public class Transaction implements java.io.Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name="TRANSACTION_CONFIG", joinColumns=@JoinColumn(name="TRANSACTION_ID"))
@MapKeyColumn(name = "PROPERTY_KEY")
@Column(name = "PROPERTY_VALUE")
protected Map<String, String> properties = new HashMap<String, String>();
public Transaction() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
}
我想通过其“属性”找到一个交易。出于这个原因,我编写了以下Spring规范类来过滤事务的属性。
public static Specification<Transaction> matches(final Map<String, String> criteria) {
return new Specification<Transaction>() {
@Override
public Predicate toPredicate(Root<Transaction> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<Predicate>();
Path<Map<String, String>> propertiesRoot = root.join("properties");
for (String key : criteria.keySet()) {
Predicate p = builder.and(propertiesRoot.in(key), propertiesRoot.in(criteria.get(key)));
predicates.add(p);
}
return builder.isTrue(propertiesRoot.in(criteria));
}
};
}
但这似乎没有任何回报。关于我做错了什么的任何想法?
答案 0 :(得分:1)
尝试以下
public static Specification<Transaction> matches(final Map<String, String> criteria) {
return new Specification<Transaction>() {
@Override
public Predicate toPredicate(Root<Transaction> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
//you can define RIGHT or INNER join if you want
MapJoin<Transaction, String, String> propertiesRoot = root.joinMap("properties", JoinType.LEFT);
for (Map.Entry entry : criteria.entrySet()) {
Predicate predicate = builder.and(
builder.equal(propertiesRoot.key(), entry.getKey()),
builder.equal(propertiesRoot.value(), entry.getValue())
);
predicates.add(predicate);
}
Predicate[] predicatesArray = predicates.toArray(new Predicate[predicates.size()]);
return builder.and(predicatesArray);
}
};
}
或者如果您使用的是Java8
public static Specification<Transaction> matches(final Map<String, String> criteria) {
return (root, query, builder) -> {
//you can define RIGHT or INNER join if you want
MapJoin<Transaction, String, String> propertiesRoot = root.joinMap("properties", JoinType.LEFT);
List<Predicate> predicates = criteria.entrySet().stream()
.map(entry ->
builder.and(
builder.equal(propertiesRoot.key(), entry.getKey()),
builder.equal(propertiesRoot.value(), entry.getValue())
))
.collect(Collectors.toList());
Predicate[] predicatesArray = predicates.toArray(new Predicate[predicates.size()]);
return builder.and(predicatesArray);
};
}
答案 1 :(得分:0)
您正在构建predicates
列表,但是您没有在返回的谓词中使用它。相反,你正在返回builder.isTrue(propertiesRoot.in(criteria))
这没有任何意义。相反,你应该
return builder.and(predicates.toArray(new Predicates[predicates.size()]))