I have two entities, Group and GroupMember. Group is like it sounds a group that has name and some other properties. Members of the group are mapped with GroupMember entity, which has an entry with a User and a Group for every group the user is member of. They look like the following:
@Entity
@Table(name = EntityTokens.GROUP_TABLE)
public class Group
{
@Id
@Column(name = EntityTokens.GROUP_ID_COLUMN)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long groupId;
...
// Group members
@OneToMany(orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "group", cascade = {CascadeType.ALL})
private Collection<GroupMember> groupMembers;
}
@Entity
@Table(name = EntityTokens.GROUP_MEMBER_TABLE)
public class GroupMember
{
@Id
@Column(name = EntityTokens.GROUP_MEMBER_ID_COLUMN)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long memberId;
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = EntityTokens.GROUP_MEMBER_ID_COLUMN)
private Group group;
}
I’m trying to write a criteria query that returns all groups that have some predefined properties and that the current user is not part of. My query looks like this:
CriteriaQuery<Group> q = cb.createQuery(Group.class);
Root<Group> root = q.from(Group.class);
Join<Group, GroupMember> groups = root.join(Group_.groupMembers);
q.select(root);
q.where(cb.notEqual(groups.get(GroupMember_.user), user),
cb.equal(root.get(Group_.global), false),
cb.equal(root.get(Group_.personal), false),
cb.equal(root.get(Group_.privacy), GroupPrivacy.PUBLIC));
q.distinct(true);
The user here represents the current user. This query doesn’t work because if there are other members that are part of the same group as me they will be included in the query result due to the join. How should the correct query look like? I’m not that familiar with the criteria query API yet.
join for a ToMany relationship is conceptually an “anyOf” operation, meaning if any of the many is true then the expression is true.
What you want is an “allOf”, criteria does not have this, you need to use a sub select for this in SQL.
The JPQL would be,
The criteria would be the same, using a sub criteria query for the exists.