为了从我的数据库中获取申请人列表,我在尝试检索时遇到了问题。
我在这个例子中知道我正在通过一个错误的方法获取:获取实体的字符串ID但这取决于重构;)
这是我的规范和带有连接的谓词循环:
public static Specification<Applicant> applicantsMatchMobility(final String... mobilities) {
return new Specification<Applicant>() {
@Override
public Predicate toPredicate(Root<Applicant> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Collection<Predicate> predicates = new ArrayList<>();
Join<Applicant, Mobility> applicantMobilityJoin = root.join("mobility");
for(String mobility : mobilities) {
predicates.add(builder.equal(applicantMobilityJoin.<Mobility>get("id"), Integer.parseInt(mobility)));
}
return builder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
}
当我只传递一个Mobility实体的id但它是一个String ids数组&gt;时,它工作正常。 1这总是返回0 ..
这是我的junit测试:
@Test
public void ShouldHaveOneApplicantWhenSearchMobilityMultipleTotallyEquals(){
String mobilitiesId[] = {"0", "1"};
List<Applicant> applicantList = applicantRepository.findAll(applicantsMatchMobility(mobilitiesId));
Assert.assertNotNull(applicantList);
Assert.assertEquals("Result", 1, applicantList.size());
Applicant applicant = applicantList.get(0);
Assert.assertNotNull(applicant);
Assert.assertEquals("Result", "XBNC", applicant.getFirstName());
}
以下是生成的请求:
select
*
from
applicant applicant0_
inner join
applicant_mobility mobility1_
on applicant0_.id=mobility1_.id_applicant
inner join
mobility mobility2_
on mobility1_.id_mobility=mobility2_.id
where
mobility2_.id=0
and mobility2_.id=1
这是我的测试数据集:
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<MOBILITY ID="0" NAME="sud"/>
<MOBILITY ID="1" NAME="nice"/>
<MOBILITY ID="2" NAME="cannes"/>
<MOBILITY ID="3" NAME="nowhere"/>
<TAGS ID="0" NAME="tags1"/>
<TAGS ID="1" NAME="tags2"/>
<TAGS ID="2" NAME="tags3"/>
<STATUS ID="0" NAME="status1"/>
<STATUS ID="1" NAME="status2"/>
<AVAILABILITY ID="0" NAME="availability1"/>
<APPLICANT ID="0" LAST_NAME="XBNC" FIRST_NAME="XBNC" YEAR="2001" WAGE_CLAIM="50" ID_STATUS="0" ID_AVAILABILITY="0" />
<APPLICANT ID="1" LAST_NAME="XBN" FIRST_NAME="XBN" YEAR="0" WAGE_CLAIM="70" ID_STATUS="1" ID_AVAILABILITY="0"/>
<APPLICANT ID="2" LAST_NAME="MI" FIRST_NAME="MI" YEAR="1995" WAGE_CLAIM="0" ID_STATUS="1" ID_AVAILABILITY="0"/>
<APPLICANT ID="3" LAST_NAME="bisTronomique" FIRST_NAME="bisTronomique" YEAR="-400" WAGE_CLAIM="0" ID_STATUS="0" ID_AVAILABILITY="0"/>
<APPLICANT_MOBILITY ID_APPLICANT="0" ID_MOBILITY="0"/>
<APPLICANT_MOBILITY ID_APPLICANT="0" ID_MOBILITY="1"/>
<APPLICANT_MOBILITY ID_APPLICANT="1" ID_MOBILITY="0"/>
<APPLICANT_MOBILITY ID_APPLICANT="1" ID_MOBILITY="2"/>
<APPLICANT_MOBILITY ID_APPLICANT="2" ID_MOBILITY="1"/>
<APPLICANT_TAGS ID_APPLICANT="0" ID_TAGS="0"/>
<APPLICANT_TAGS ID_APPLICANT="0" ID_TAGS="1"/>
<APPLICANT_TAGS ID_APPLICANT="0" ID_TAGS="2"/>
</dataset>
您是否可以在此测试中看到我只需要回到&#34; XBNC&#34;申请人因为他包含2个相应的MobilityeID ..
答案 0 :(得分:1)
这是一个基本的SQL逻辑问题,我猜你正在尝试检索对应于mobiliy ID 0和1的2行:当前代码中的where子句(critria)构建[where id ='0'< b>和 id ='1'],由于特定的表字段不能同时等于两个值,因此总是不返回任何行。
而不是and()
,您需要使用or()
方法,它将构建一个where子句,如[where id ='0'或 id ='1']。只提供一行和一行只将mobilityID设置为1,而一行和一行只将mobilityID设置为0,那么您应该从运行查询中获得两行。
更新
在您的问题编辑后,我想我可以看到您的问题所在。这仍然是一个SQL问题,但这意味着您的查询需要稍微复杂一些。您需要获得如下查询:
select
*
from
applicant applicant0_
inner join
applicant_mobility mobility1_
on applicant0_.id=mobility1_.id_applicant
inner join
mobility mobility2_
on mobility1_.id_mobility=mobility2_.id
where
exists (
select * from applicant_mobility
where id_applicant = applicant0_.id
and id_mobility = 1;
)
and
exists (
select * from applicant_mobility
where id_applicant = applicant0_.id
and id_mobility = 0;
)
请注意子查询中applicant
和applicant_mobility
之间的联接。这实际上是这样说的:对于主要查询找到的每个申请者实例,验证它是否在至少有一个移动性设置为0的相应applicant_mobility实例的集合中,以及另一个移动性设置为1的实例。
因此,您的函数中的循环需要为每个提供的移动设备ID创建子查询,然后使用构建器and()
和exists()
将它们组合在一起。
答案 1 :(得分:0)
添加@NotSoOldNick指定的内容。您似乎需要的是一个IN子句,只能检索匹配的移动性匹配的申请人。您可以将其更改为以下或稍微类似。
public static Specification<Applicant> applicantsMatchMobility(final String... mobilities) {
return new Specification<Applicant>() {
@Override
public Predicate toPredicate(Root<Applicant> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Collection<Predicate> predicates = new ArrayList<>();
Join<Applicant, Mobility> applicantMobilityJoin = root.join("mobility");
Expression<String> idExp = applicantMobilityJoin.<Mobility>get("id");
return builder.and(idExp.in(mobilities));
}
};
}