加入ElementCollections以找到至少一个匹配项

时间:2015-04-15 07:59:07

标签: java jpa eclipselink criteria

我有以下实体,为此示例进行了简化:

@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,则始终匹配)。

任何提示?

1 个答案:

答案 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);