Java JPA CriteriaQuery,查询未按预期返回结果的多个字段
我有一个基本的留言板类型的系统,我正在基于spring的webapp中开发。我正在使用Spring4.1.3和Hibernate4.3.7。我正试图构建一个通用搜索栏来查找在许多字段中包含指定值的帖子。首先,这里是我的后域对象:Java JPA CriteriaQuery,查询未按预期返回结果的多个字段,java,sql,hibernate,jpa,dao,Java,Sql,Hibernate,Jpa,Dao,我有一个基本的留言板类型的系统,我正在基于spring的webapp中开发。我正在使用Spring4.1.3和Hibernate4.3.7。我正试图构建一个通用搜索栏来查找在许多字段中包含指定值的帖子。首先,这里是我的后域对象: @Entity public class Post implements Serializable { @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PER
@Entity
public class Post implements Serializable {
@ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(
name = "POST_KEYWORD",
joinColumns = {@JoinColumn(name = "POST_ID", referencedColumnName = "POST_ID")},
inverseJoinColumns = {@JoinColumn(name = "KEYWORD_ID", referencedColumnName = "ID")}
)
private Set<Keyword> keywords = new HashSet<>();
}
author和category类没有int计数,只有id和value字段
这是我的贴子:
public List<Post> universalFind(String value, int maxResults) {
// create a new string that is built for case insensitive "like" sql searches
String upperValue = "%" + value.toUpperCase() + "%";
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// build the criteria query and get the path for the category value
CriteriaQuery<Post> postQuery = criteriaBuilder.createQuery(Post.class).distinct(true);
Root<Post> postRoot = postQuery.from(Post.class);
List<Predicate> predicates = new ArrayList<>();
// find titles containing the value
Predicate titlePredicate = criteriaBuilder.like(criteriaBuilder.upper(postRoot.get(Post_.title)), upperValue);
predicates.add(titlePredicate);
// find keywords containing the value
SetJoin<Post, Keyword> postKeywords = postRoot.join(Post_.keywords);
Path<String> keywordPath = postKeywords.get(Keyword_.value);
Predicate keywordPredicate = criteriaBuilder.like(criteriaBuilder.upper(keywordPath), upperValue);
predicates.add(keywordPredicate);
select.where(criteriaBuilder.or(predicates.toArray(new Predicate[]{})));
TypedQuery typedQuery = entityManager.createQuery(select);
List<Post> resultList = typedQuery.getResultList();
return resultList;
}
当所有数据都填充到Post对象中时,它会按预期工作。如果我有两篇文章的标题中有Test,并且我搜索Test,我会把这两篇文章都拿回来。但是,如果我删除其中一篇文章中的所有关键字,该文章将不再显示在搜索结果中。我可以使用pgadmin来验证它是否在数据库中
如果我在DAO中注释掉关键字的SetJoin部分,没有关键字的帖子会突然出现在我的搜索中
有没有什么方法可以防止这种情况发生,这样我就可以拥有一篇没有关键字的帖子,如果搜索词与其他任何一个字段匹配,它仍然会显示在结果中
编辑:我把这段代码缩减到了我能做到的最简单的弗兰肯斯坦代码你包含的代码太多了,任何人都无法涉过并试图解决你的问题。试着把它缩小到一个实际上可以检查的范围。这不是一个代码审查网站。真的吗?2个实体类,没有逻辑,只显示属性/注释,dao方法用我正在构建的谓词显示CriteriaQuery,这太过分了?这似乎是我可能包含的最低代码量。它有100多行代码,在这个网站上没有人有义务帮助你。这可能是代码的最低数量,但你比任何人都早了三个多小时,甚至没有人对你的帖子发表评论。这远远高于这里的平均水平。我只是提供一些友好的建议。如果你不能为我们缩小这个问题的范围,那就祝你好运,自己解决吧。我知道没有人有义务帮忙。我在这个网站上呆了很长时间。如果你没有提供足够的信息,人们会让你知道他们无法在没有看到违规代码的情况下帮助你。从字面上讲,前两个代码块是成员变量,带有JPA注释,这对于理解问题至关重要。不需要筛选,它只是一个简单的豆子。下面的代码块是一个CriteriaQuery,它对我展示的实体进行操作,显示定义查询的谓词。我会继续删掉一些东西,但我强烈不同意这是一个疯狂的代码量。
public List<Post> universalFind(String value, int maxResults) {
// create a new string that is built for case insensitive "like" sql searches
String upperValue = "%" + value.toUpperCase() + "%";
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// build the criteria query and get the path for the category value
CriteriaQuery<Post> postQuery = criteriaBuilder.createQuery(Post.class).distinct(true);
Root<Post> postRoot = postQuery.from(Post.class);
List<Predicate> predicates = new ArrayList<>();
// find titles containing the value
Predicate titlePredicate = criteriaBuilder.like(criteriaBuilder.upper(postRoot.get(Post_.title)), upperValue);
predicates.add(titlePredicate);
// find keywords containing the value
SetJoin<Post, Keyword> postKeywords = postRoot.join(Post_.keywords);
Path<String> keywordPath = postKeywords.get(Keyword_.value);
Predicate keywordPredicate = criteriaBuilder.like(criteriaBuilder.upper(keywordPath), upperValue);
predicates.add(keywordPredicate);
select.where(criteriaBuilder.or(predicates.toArray(new Predicate[]{})));
TypedQuery typedQuery = entityManager.createQuery(select);
List<Post> resultList = typedQuery.getResultList();
return resultList;
}