我有以下实体,为此示例进行了简化:
@Entity
public class Subscription {
@Column
private String user;
@Column
private String sportsTeam;
@ElementCollection
@CollectionTable(joinColumns= @JoinColumn(name="subscription"))
private Set<String> opponents;
@ElementCollection
@CollectionTable(joinColumns= @JoinColumn(name="subscription"))
private Set<String> matchTypes;
}
这用于订阅服务,您可以在其中获得您的团队所玩的匹配结果。用户总是订阅一个团队(例如曼联),零个或多个对手(其中一个空列表表示您对所有对手感兴趣,一个或多个值意味着只有当团队正在玩这个时才会收到通知对手)和零或多种比赛类型(例如'友好','国内联赛'或'冠军联赛'。
我有一个对象,它保存单个匹配的结果,我试图找出如何询问数据库哪些订阅对这些结果感兴趣。
我的尝试如下:
final CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
final CriteriaQuery<Subscription> cq = cb.createQuery(Subscription.class);
final Root<Subscription> root = cq.from(Subscription.class);
final Expression<String> sportsTeam = root.get("sportsTeam");
final Predicate forSportsTeam = cb.equal(sportsTeam, obj.getSportsTeam());
final Expression<Collection<String>> opponents = root.get("opponents");
final Predicate againstOpponent = cb.isMember(obj.getOpponent(), opponents);
final Expression<Collection<String>> matchTypes = root.get("matchTypes");
final Predicate withMatchType = cb.isMember(obj.getMatchType(), matchTypes);
cq.select(root).where(forSportsTeam, cb.or(againstOpponent, withMatchType));
final TypedQuery<Subscription> qry = this.entityManager.createQuery(cq);
final List<DSubscription> subscriptions = qry.getResultList();
问题在于它为对手和matchtypes生成内部联接:
SELECT t0.ID
,t0.user
,t0.sportsteam
FROM Subscription_MATCHTYPES t2
,Subscription_OPPONENTS t1
,subscription t0
WHERE (t0.sportsteam = 'Manchester United')
AND ((t1.teamName = 'Manchester City') OR (t2.matchType = 'domestic league'))
AND (t1.subscription = t0.ID) AND (t2.subscription = t0.ID)
因此,如果对手匹配订阅,但没有为订阅选择matchType,则会得到0结果。
我正在寻找的是,如果我正在检查的结果对象与此订阅的至少一个对手匹配(或者如果此订阅未指定对手则匹配),则结果查询将给出1个结果至少有一个matchType(如果没有为订阅指定matchTypes,则始终匹配)。
任何提示?
答案 0 :(得分:1)
我正在寻找的是,如果结果对象我检查与此订阅的至少一个对手的匹配(或者如果此订阅不匹配),则结果查询将给出1个结果。指定对手)......
变化:
final Predicate againstOpponent = cb.isMember(obj.getOpponent(), opponents);
为:
final Predicate againstOpponent = cb.or(cb.isEmpty(opponents), cb.isMember(obj.getOpponent(), opponents));
...并与至少一个matchType匹配(如果没有为订阅指定matchTypes,则始终匹配)。
变化:
final Predicate withMatchType = cb.isMember(obj.getMatchType(), matchTypes);
为:
final Predicate withMatchType = cb.or(cb.isEmpty(matchTypes), cb.isMember(obj.getMatchType(), matchTypes));
您可能还需要更改您的查询(不确定我是否正确理解此部分):
cq.select(root).where(forSportsTeam, cb.or(againstOpponent, withMatchType));
为:
cq.select(root).where(cb.and(forSportsTeam, againstOpponent, withMatchType));
或简单地说:
cq.select(root).where(forSportsTeam, againstOpponent, withMatchType);