У меня есть следующая модель;
Вот класс UserEntity:
class UserEntity {
private String username;
private List<RuleEntity> rules;
@Column(name = "username", nullable = false, unique = true)
public String getUsername() {
return username;
}
@ManyToMany(mappedBy="users" , fetch = FetchType.LAZY)
public List<RuleEntity> getRules() {
return rules;
}
...
}
И класс RuleEntity:
class RuleEntity {
private String name;
private List<UserEntity> users;
@Column(name = "name", nullable = false)
public String getRuleName() {
return ruleName;
}
@ManyToMany (fetch = FetchType.LAZY)
@JoinTable(name= "RULE_USER" ,joinColumns=@JoinColumn
(name=RuleEntity.RULE_ID, referencedColumnName="ID", insertable = true, updatable = false, nullable = false),
inverseJoinColumns=@JoinColumn
(name=UserEntity.USER_ID, referencedColumnName="ID", insertable = true, updatable = false, nullable = false),
uniqueConstraints = @UniqueConstraint(columnNames = {RuleEntity.RULE_ID, UserEntity.USER_ID}))
public List<UserEntity> getUsers() {
return users;
}
...
}
Я пытаюсь выполнить поиск, посредством которого пользователь может выполнить поиск, используя:
Поэтому я выполняю 2 запроса HQL, один для возврата соответствующих пользователей и один для возврата соответствующих правил, например
public SearchResults search(String maybePartialUsername, String maybePartialRuleName) {
List<UserEntity> userEntities = hqlQuery("select distinct users from UserEntity as users inner join users.rules as rules where users.username like :maybePartialUsername and rules.ruleName like :maybePartialRuleName");
List<RuleEntity> ruleEntities = hqlQuery("select distinct rules from RuleEntity as rules inner join rules.users as users where users.username like :maybePartialUsername and rules.ruleName like :maybePartialRuleName");
return SearchResults(userEntities, ruleEntities);
}
Первый запрос HQL для поиска пользователей, соответствующих имени пользователя (и/или имени), отлично работает, когда пользователь является членом хотя бы одного правила, но не возвращает никаких результатов, когда пользователь не был добавлен ни к каким правилам.
Изменение "внутреннего соединения" на "левое соединение" не помогает. Проблема заключается в условии "rules.ruleName like: maybePartialRuleName", если я удалю этот запрос, но мне нужно это в запросе в случаях, когда успешное соединение с таблицами правил (т.е. у пользователя есть правила), и поэтому мне нужно фильтровать по имени правила, а также по имени пользователя.
select distinct users from UserEntity as users inner join users.rules as rules where users.username like :maybePartialUsername and rules.ruleName like :maybePartialRuleName
Это то, что сработало для меня (спасибо @sergiu):
Следующий метод создает выбранную часть запроса:
public List<UserEntity> search(final String maybePartialUsername, final String maybePartialRuleName)
throws EntityException {
final String selectUsersStatement = "select distinct users from UserEntity as users";
final String joinUsersWithRulesClause = shouldFilterSearchBy(maybePartialRuleName) ? "inner join users.rules as rules" : null;
return search(Joiner.on(" ").skipNulls().join(selectUsersStatement, joinUsersWithRulesClause),
maybePartialUsername, maybePartialRuleName);
}
Затем он вызывает метод (не показан), который вызывает следующее для построения тех частей запроса:
private String buildSearchQueryFrom(final String selectStatement, final String maybePartialUsername,
final String maybePartialRuleName) {
final Collection<String> searchFilters = Lists.newArrayListWithCapacity(2);
if (shouldFilterSearchBy(maybePartialUsername)) {
searchFilters.add("users.username like :maybePartialUsername");
}
if (shouldFilterSearchBy(maybePartialRuleName)) {
searchFilters.add("rules.ruleName like :maybePartialRuleName");
}
final String whereClauseParts = Joiner.on(" and ").skipNulls().join(searchFilters);
return Joiner.on(" where ").skipNulls().join(selectStatement, whereClauseParts);
}
И вспомогательный метод, называемый методом выше:
protected boolean shouldFilterSearchBy(final String searchValue) {
return !Strings.isNullOrEmpty(searchValue);
}
Попробуйте присоединиться
выберите отдельных пользователей из UserEntity, так как пользователи оставили join users.rules как правила, где users.username like: maybePartialUsername и rules.ruleName like: maybePartialRuleName.
Это даст вам все, что в левой части (userEntity в этом случае).