2013-06-28 3 views
3

У меня есть сущности User, Organization и GrantedRole. Их отношение состоит в том, что GrantedRole определяет роль, которую Пользователь имеет в Организации. Все три объекта наследуют поле «id» (аннотированное с помощью @Id) из своего суперкласса. Организация не имеет ссылок на GrantedRole или User, эти отношения однонаправлены.JPA Присоединиться к нескольким столбцам

@Entity 
@Table(name = "role_assignments", uniqueConstraints = @UniqueConstraint(columnNames = { 
    "user_id", "organization_id" })) 
public class GrantedRole extends DomainEntity implements GrantedAuthority { 

    public static enum Role { 
     ROLE_MODM_USER, ROLE_MODM_ORGADMIN, ROLE_MODM_ADMIN 
    } 

    private User user; 
    private Role role; 
    private Organization organization; 

    public static enum Role { 
     ROLE_MODM_USER, ROLE_MODM_ORGADMIN, ROLE_MODM_ADMIN 
    } 

    @ManyToOne 
    @NotNull 
    public User getUser() { 
     return user; 
    } 

    @NotNull 
    @Enumerated(EnumType.STRING) 
    public Role getRole() { 
     return role; 
    } 

    @ManyToOne 
    public Organization getOrganization() { 
     return organization; 
    } 

    // Some setters 
} 

@Entity 
@Table(name = "modmUsers") 
public class User extends DomainEntity implements UserDetails { 
    // Some other fields 

    private Set<GrantedRole> roles = new HashSet<GrantedRole>(); 
    private Set<Organization> organizations = new HashSet<Organization>(); 

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user") 
    public Set<GrantedRole> getRoles() { 
     return roles; 
    } 

    @ManyToMany(fetch = FetchType.EAGER) 
    public Set<Organization> getOrganizations() { 
     return organizations; 
    } 

    // Some setters 
} 

Теперь я хочу использовать JPA критерии, чтобы найти организации, в которых пользователь имеет роль ROLE_MODM_ORGADMIN. Но сгенерированный запрос объединяется в один столбец, что приводит к повторению строк из GrantedRole, поскольку User.id не уникален в GrantedRole и не является Organization.id. Комбинация обоих уникальна.

Мой код для нахождения организации:

public List<Organization> findOrganizationsByOrgAdminUser(String 
    CriteriaBuilder cb = entityManager. 
    CriteriaQuery<Organization> query = cb.createQuery(Organization. 
    Root<User> root = query.from(User.class); 
    SetJoin<User, Organization> joinOrg = root.joinSet("organizations"); 
    SetJoin<User, GrantedRole> joinRoles = root.joinSet("roles"); 

    Predicate p1 = cb.equal(root.get("id"), userId); 
    Predicate p2 = cb.equal(joinRoles.get("role"), Role.ROLE_MODM_ORGADMIN); 

    query.select(joinOrg); 
    query.where(cb.and(p1, p2)); 

    return entityManager.createQuery(query).getResultList(); 
} 

Сформированный запрос является:

SELECT 
    orgs.* 
FROM 
    modmUsers users 
INNER JOIN 
    modmUsers_organizations u_o 
     ON users.id=u_o.modmUsers_id 
INNER JOIN 
    organizations orgs 
     ON u_o.organization_id=orgs.id 
INNER JOIN 
    role_assignments roles 
     ON users.id=roles.user_id 
WHERE 
    users.id=? 
    and roles.role=? 

Запрос Я хочу это:

SELECT 
    orgs.* 
FROM 
    modmUsers users 
INNER JOIN 
    modmUsers_organizations u_o 
     ON users.id=u_o.modmUsers_id 
INNER JOIN 
    organizations orgs 
     ON u_o.organization_id=orgs.id 
INNER JOIN 
    role_assignments roles 
     ON users.id=roles.user_id 
     AND orgs.id=roles.organization_id //how to do this??? 
WHERE 
    users.id=? 
    and roles.role=? 

ответ

3

Итак, мой коллега помог вне меня и повел меня по этому вопросу:

SELECT 
    orgs.* 
FROM 
    modmUsers users 
INNER JOIN 
    modmUsers_organizations u_o 
     ON users.id=u_o.modmUsers_id 
INNER JOIN 
    organizations orgs 
     ON u_o.organization_id=orgs.id 
INNER JOIN 
    role_assignments roles 
     ON users.id=roles.user_id 
WHERE 
    users.id=? 
    AND roles.role=? 
    AND orgs.id=roles.organization_id 

Который является простым расширением моего кода:

public List<Organization> findOrganizationsByOrgAdminUser(String 
    CriteriaBuilder cb = entityManager. 
    CriteriaQuery<Organization> query = cb.createQuery(Organization. 
    Root<User> root = query.from(User.class); 
    SetJoin<User, Organization> joinOrg = root.joinSet("organizations"); 
    SetJoin<User, GrantedRole> joinRoles = root.joinSet("roles"); 

    Predicate p1 = cb.equal(root.get("id"), userId); 
    Predicate p2 = cb.equal(joinRoles.get("role"), Role.ROLE_MODM_ORGADMIN); 
    Predicate p3 = cb.equal(joinOrg.get("id"), joinRoles.get("organization")); 

    query.select(joinOrg); 
    query.where(cb.and(p1, p2, p3)); 

    return entityManager.createQuery(query).getResultList(); 
}