TK-Mybatis的Example的一些用法
背景
最近項目中使用tk-mybatis遇到了一些問題:
問題詳情:
(A=A1 and B=B1) or (A=A2 and B=B2) and C IN (C1,C2)
抽象一點:
A or B and C
實際執行方式為:
A or (B and C)
實際期望:
(A or B ) and C
代碼
有問題的代碼為:
List<Map<String, String>> properties = new ArrayList<>();
Example example = new Example(Country.class);
properties.forEach(map -> {
Example.Criteria criteria = example.createCriteria();
map.forEach((key, value) -> criteria.andEqualTo(key, value));
example.or(criteria);
});
Example.Criteria criteria = example.createCriteria()
.andIn("countryname", Arrays.asList("CN", "US", "UK"));
example.and(criteria);
CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
mapper.selectByExample(example);
最終生成的sql為:
(A=A1 and B=B1) or (A=A2 and B=B2) and C IN (C1,C2)
每個粗體代表一個criteria
很明顯不符合預期
解決方案
只能手寫sql進行組裝
// 這里組裝sql
String sql = properties.stream()
.map(map ->
map.entrySet()
.stream()
.map(item -> String.format("`%s` = '%s'", item.getKey(), item.getValue()))
.collect(Collectors.joining(" and ", " ( ", " ) "))
).collect(Collectors.joining(" or "));
//這里只有一個criteria 就可以避免問題
example.createCriteria().andCondition(sql);
//其他一樣的
Example.Criteria criteria1 = example.createCriteria()
.andIn("countryname", Arrays.asList("CN", "US", "UK"));
example.and(criteria1);
CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
mapper.selectByExample(example);
生成sql為:
((A=A1 and B=B1) or (A=A2 and B=B2)) and C IN (C1,C2)
每個粗體代表一個criteria
核心解決方案
讓OR語句生成一個criteria,之后就不會影響后續的步驟了。