我有两张表有很多对很多的关系。 1表是用户,第二个表是组。这意味着1个用户可以拥有多个组。而1组可以有很多用户。这是我桌子的内容:
Table User Table Group
+------------------------------+ +-----------------------------+
| Name | Age | Group | | Name | User |
+------------------------------+ +-----------------------------+
|Fikrie | 21 | Unix | | Unix | Fikrie, Fikrie1 |
|Fikrie1 | 22 | Windows | | Windows | Fikrie1,Fikrie2 |
|Fikrie2 | 23 | Unix,Windows | | HP-UX | |
|Lucy | 21 | | +-----------------------------+
|Lucy1 | 22 | |
+------------------------------+
每当我尝试查询时,我只设法让拥有组的用户。对于可能的情况,我只能设法得到所有的Fikries。为什么我的查询缺少Lucys?这是我的代码:
public List<User> retrieveAll(String nameFilter, String groupFilter, int start, int length) {
logger.info("nameFilter = [" + nameFilter + "]");
logger.info("groupFilter = [" + groupFilter + "]");
logger.info("start is = [" + start + "]");
logger.info("length is = [" + length + "]");
ServiceUtil.requireAdmin();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> q = cb.createQuery(User.class);
Root<User> c = q.from(User.class);
Join<User, UserGroup> usrGrp = c.join(
User_.userGroups, JoinType.LEFT);
q.select(c);
Predicate namePredicate = cb.like(c.get(User_.name), "%"
+ nameFilter.toLowerCase() + "%");
Predicate groupPredicate = cb.like(usrGrp.get(UserGroup_.name),
"%" + groupFilter.toLowerCase() + "%");
Predicate andPredicate = cb.and(namePredicate, groupPredicate);
q.where(andPredicate);
List<User> results = em.createQuery(q).setFirstResult(start)
.setMaxResults(length).getResultList();
int i = 0;
for (User usr : results) {
logger.info("Name=" + usr.getName());
for (UsrGroup usrgroup2 : usr.getUserGroups()) {
logger.info("usrgroups = [" + usrgroup2.getName() + "]");
}
}
return results;
}
这是运行查询后的日志:
nameFilter = []
groupFilter = []
start is = [0]
length is = [5]
Name=Fikrie
usrgroups = [Unix]
Name=Fikrie1
usrgroups= [Windows]
Name=Fikrie2
usrgroups= [Unix]
usrgroups= [Windows]
从this文档中,它表示使用Left类型的连接来应用左外连接。为什么它仍然缺少没有任何组的其他2个用户?根据我的理解,通过引用here,左外连接应该可以解决问题。
我尝试了什么:
删除groupPredicate
,只需按名称进行过滤。然后我得到所有用户。
记录结果:
nameFilter = []
groupFilter = []
start is = [0]
length is = [5]
Name=Fikrie
usrgroups = [Unix]
Name=Fikrie1
usrgroups= [Windows]
Name=Fikrie2
usrgroups= [Unix]
usrgroups= [Windows]
Name=Lucy
Name=Lucy1
根据我的理解,如果我不按群组查询,它将全部返回。但是,如果我按组添加谓词,那么它将过滤掉用户,包括那些具有空组的用户。这是LEFT
类型的加入的默认行为吗?我只想过滤掉有组的用户。对于没有的用户,我不想过滤。是否可以在criteriabuilder中这样做?
更新
我想也许它不是因为外连接而是因为查询本身。为了确认这一点,我在Table User中添加了另一列,如下所示:
Table User
+-------------------------------------------+
| Name | Age | Group | Skill |
+-------------------------------------------+
|Fikrie | 21 | Unix | <NULL> |
|Fikrie1 | 22 | Windows | <NULL> |
|Fikrie2 | 23 | Unix,Windows | <NULL> |
|Lucy | 21 | | killer |
|Lucy1 | 22 | | <NULL> |
+-------------------------------------------+
然后我将查询更改为:
q.select(c);
Predicate namePredicate = cb.like(c.get(User_.name), "%"
+ nameFilter.toLowerCase() + "%");
Predicate skillPredicate = cb.like(c.get(User_.skill),
"%" + groupFilter.toLowerCase() + "%");
Predicate andPredicate = cb.and(namePredicate, skillPredicate);
q.where(andPredicate);
List<User> results = em.createQuery(q).setFirstResult(start)
.setMaxResults(length).getResultList();
int i = 0;
for (User usr : results) {
logger.info("Name=[" + usr.getName() + "], skill=" + usr.getSkill() + "]");
}
return results;
这是新测试的日志:
nameFilter = []
groupFilter = []
start is = [0]
length is = [5]
Name=[Lucy], skill=[killer]
我不是100%肯定,但我认为我的查询在处理NULL值时遇到问题。