【问题标题】:Joining to ElementCollections to find at least one match加入 ElementCollections 以找到至少一个匹配项
【发布时间】:2015-04-15 07:59:06
【问题描述】:

我有以下实体,为本示例简化:

@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();

问题在于它会为对手和匹配类型生成内连接:

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(如果没有为订阅指定 matchType,则始终匹配)。

有什么建议吗?

【问题讨论】:

    标签: java jpa eclipselink criteria


    【解决方案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);
    

    【讨论】:

    • 我目前没有时间尝试这个(希望明天),但一旦我这样做并且它有效,我会接受。
    猜你喜欢
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多