JPA规范在使用CriteriaBuilder.or()方法时无效。

huangapple go评论96阅读模式
英文:

JPA specification has no effect with CriteriaBuilder.or() method

问题

以下是翻译好的部分:

public class VendorEmailSpecification {
    public static Specification<VendorEmail> filter(String filterText) {
        return new Specification<VendorEmail>() {
            @Override
            public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();

                if (!StringUtils.isEmpty(filterText)) {
                    /***
                     * 这个代码块没有任何效果
                     **/
                    predicate = criteriaBuilder.or(
                            criteriaBuilder.like(root.get("to"), "%" + filterText + "%"),
                            criteriaBuilder.like(root.get("from"), "%" + filterText + "%"),
                            criteriaBuilder.like(root.get("subject"), "%" + filterText + "%"),
                            criteriaBuilder.like(root.get("message"), "%" + filterText + "%")
                    );
                }
                // 存在 ManyToOne 关联,AuthUserThread.getContext() 返回一个 User 实体对象,这部分正常工作
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext()));

                return predicate;
            }
        };
    }
}

如果你需要进一步讨论或有其他问题,请随时提问。

英文:

What I want to get is like -

SELECT * FROM emials WHERE user_id = ?1 AND (`to` like &#39;%?2%&#39; OR `from` LIKE &#39;%?2%&#39; OR subject LIKE &#39;%?2%&#39;);

To get such I have following specification like -

public class VendorEmailSpecification {
    public static Specification&lt;VendorEmail&gt; filter(String filterText) {
        return new Specification&lt;VendorEmail&gt;() {
            @Override
            public Predicate toPredicate(Root&lt;VendorEmail&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();

                if(!StringUtils.isEmpty(filterText)) {
                    /***
                    * this block donot have any effects
                    **/
                    predicate = criteriaBuilder.or(
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;to&quot;),&quot;%&quot;+ filterText +&quot;%&quot;)),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;from&quot;),&quot;%&quot;+ filterText +&quot;%&quot;)),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;subject&quot;),&quot;%&quot;+ filterText +&quot;%&quot;)),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;message&quot;),&quot;%&quot;+ filterText +&quot;%&quot;))
                   );
                }
                // there is an relation of ManyToOne with user and AuthUserThread.getContext() gives an object of User entity.
                // this working perfectly
                predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(root.get(&quot;user&quot;), AuthUserThread.getContext()));


                return predicate;
            }
        };
    }
}

What mistake is there and how can i fix that?

答案1

得分: 1

看起来 filterText 参数在调用 toPredicate() 方法时已经超出了作用域。

如果您在 filter() 方法返回的匿名 Specification<VendorEmail> 实例中添加一个成员,并将 filterText 参数的值赋给该成员,然后更新其余代码以引用这个新成员,如下所示,应该可以解决这个问题:

public class VendorEmailSpecification {
    public static Specification<VendorEmail> filter(String filterText) {
        return new Specification<VendorEmail>() {
            private String filterValue = filterText;

            @Override
            public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();
                if (!StringUtils.isEmpty(this.filterValue)) {
                    /***
                    * this block donot have any effects
                    **/
                    predicate = criteriaBuilder.or(
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("to"), "%" + this.filterValue + "%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("from"), "%" + this.filterValue + "%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("subject"), "%" + this.filterValue + "%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("message"), "%" + this.filterValue + "%"))
                    );
                }
                // there is a relation of ManyToOne with user and AuthUserThread.getContext() gives an object of User entity.
                // this working perfectly
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext()));
                return predicate;
            }
        };
    }
}
英文:

It looks like the filterText parameter will have gone out of scope when the toPredicate() method is called.

If you add a member to the anonymous Specification&lt;VendorEmail&gt; instance returned by the filter() method, assign the value of the filterText parameter to the member, and update the remaining code to refer to the new member, as shown below, that should resolve the problem:

public class VendorEmailSpecification {
public static Specification&lt;VendorEmail&gt; filter(String filterText) {
return new Specification&lt;VendorEmail&gt;() {
private String filterValue = filterText;
@Override
public Predicate toPredicate(Root&lt;VendorEmail&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder criteriaBuilder) {
Predicate predicate = criteriaBuilder.conjunction();
if(!StringUtils.isEmpty(this.filterValue)) {
/***
* this block donot have any effects
**/
predicate = criteriaBuilder.or(
criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;to&quot;),&quot;%&quot;+ this.filterValue +&quot;%&quot;)),
criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;from&quot;),&quot;%&quot;+ this.filterValue +&quot;%&quot;)),
criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;subject&quot;),&quot;%&quot;+ this.filterValue +&quot;%&quot;)),
criteriaBuilder.or(predicate, criteriaBuilder.like(root.get(&quot;message&quot;),&quot;%&quot;+ this.filterValue +&quot;%&quot;))
);
}
// there is an relation of ManyToOne with user and AuthUserThread.getContext() gives an object of User entity.
// this working perfectly
predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(root.get(&quot;user&quot;), AuthUserThread.getContext()));
return predicate;
}
};
}
}

答案2

得分: 1

我用另一种方法解决了这个问题 -

    public class VendorEmailSpecification {
        public static Specification<VendorEmail> filter(String filterText) {
            return new Specification<VendorEmail>() {
                @Override
                public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                    Predicate predicate = criteriaBuilder.conjunction();
                    predicate = criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext());
                    if(!StringUtils.isEmpty(filterText)) {
                        Predicate toPredicate = criteriaBuilder.like(root.get("to"), "%" + filterText + "%");
                        Predicate fromPredicate = criteriaBuilder.like(root.get("from"), "%" + filterText + "%");
                        Predicate subjectPredicate = criteriaBuilder.like(root.get("subject"), "%" + filterText + "%");
                        Predicate messagePredicate = criteriaBuilder.like(root.get("message"), "%" + filterText + "%");
                        Predicate orPredicate = criteriaBuilder.or(toPredicate, fromPredicate, subjectPredicate, messagePredicate);
                        predicate = criteriaBuilder.and(predicate, orPredicate);
                        return predicate;
                    }
    
                    predicate = criteriaBuilder.and(predicate);
                    return predicate;
                }
            };
        }
    }
英文:

I solve this problem in another way -

public class VendorEmailSpecification {
public static Specification&lt;VendorEmail&gt; filter(String filterText) {
return new Specification&lt;VendorEmail&gt;() {
@Override
public Predicate toPredicate(Root&lt;VendorEmail&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder criteriaBuilder) {
Predicate predicate = criteriaBuilder.conjunction();
predicate = criteriaBuilder.equal(root.get(&quot;user&quot;), AuthUserThread.getContext());
if(!StringUtils.isEmpty(filterText)) {
Predicate toPredicate = criteriaBuilder.like(root.get(&quot;to&quot;), &quot;%&quot;+filterText+&quot;%&quot;);
Predicate fromPredicate = criteriaBuilder.like(root.get(&quot;from&quot;), &quot;%&quot;+filterText+&quot;%&quot;);
Predicate subjectPredicate = criteriaBuilder.like(root.get(&quot;subject&quot;), &quot;%&quot;+filterText+&quot;%&quot;);
Predicate messagePredicate = criteriaBuilder.like(root.get(&quot;message&quot;), &quot;%&quot;+filterText+&quot;%&quot;);
Predicate orPredicate = criteriaBuilder.or(toPredicate, fromPredicate, subjectPredicate, messagePredicate);
predicate = criteriaBuilder.and(predicate, orPredicate);
return predicate;
}
predicate = criteriaBuilder.and(predicate);
return predicate;
}
};
}
}

huangapple
  • 本文由 发表于 2020年4月5日 16:58:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/61040190.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定