QueryDsl проекция ElementCollection - PullRequest
0 голосов
/ 24 марта 2020

Я пытаюсь выяснить, как сделать DTO-проекцию сущности со списком Enums (@ElementCollection). К сожалению, документация QueryDsl отсутствует, и здесь я нахожу только результаты для версии 3, которые не применимы для версии 4.

@Entity
public class User {
    private String username;

    @Enumerated(EnumType.STRING)
    @ElementCollection(targetClass = Permission.class)
    private Set<Permission> permissions;
}

И я хотел бы DTO с набором / list / array либо Permission-Enums или просто Strings (будет преобразован в JSON в любом случае). Простое выражение конструктора не работает:

List<UserDto> users = new JPAQueryFactory(eM).select(
            Projections.constructor(UserDto.class,
                    QUser.user.username, QUser.user.permissions))
            .from(QUser.user)
            .fetch();

Дает мне org.hibernate.QueryException: not an entity

Все примеры с .transform(), которые я видел, используют groupBy и возвращают Map. Я генерирую эти запросы динамически, и мне нужен Список DTO, а не иногда Список DTO, а иногда и Карта. PostgreSQL query:

select id, username, array_remove(array_agg(up.permissions), null) as permissions
from users u
left join users_permissions up on up.uid = u.id
group by u.id;

EDIT 2:

Полагаю, это то, что мне нужно сделать с JPQL? : puke:

List<UserDto> users = (List<UserDto>) eM.getEntityManager().createQuery(
                "SELECT u.id, u.username, u.tenantId, u.fullname, u.active, u.localeKey, perms " +
                        "FROM User u " +
                        "LEFT JOIN u.permissions perms")
                .unwrap(org.hibernate.query.Query.class)
                .setResultTransformer(
                        new ResultTransformer() {
                            private Map<Long, UserDto> res = new HashMap<>();

                            @Override
                            public Object transformTuple(Object[] tuple, String[] aliases) {
                                UserDto u = res.get(tuple[0]);
                                if (u == null) {
                                    u = new UserDto((Long) tuple[0], (String) tuple[1], "", (String) tuple[2], (String) tuple[3], (boolean) tuple[4], (String) tuple[5], EnumSet.of((Permission) tuple[6]));
                                    res.put(u.getId(), u);
                                } else {
                                    u.getPermissions().add((Permission) tuple[6]);
                                }

                                return null;
                            }

                            @Override
                            public List<UserDto> transformList(List tuples) {
                                return new ArrayList<>(res.values());
                            }
                        })
                .getResultList();

1 Ответ

0 голосов
/ 24 марта 2020

ОК, я наконец понял это. В этом случае вам действительно нужно использовать преобразователь, что имеет смысл, поскольку вы хотите объединить несколько строк.

Мне пришлось копаться в модульных тестах QueryDsl . Импорт stati c на самом деле усложняет ситуацию, если вы не используете IDE, но читайте его на Github, как я. У меня почти было Решение, но я использовал Expressions.set() вместо GroupBy.set():

List<UserDto> users = new JPAQueryFactory(eM.getEntityManager())
                .selectFrom(QUser.user)
                .leftJoin(QUser.user.permissions, perm)
                .transform(
                        groupBy(QUser.user.id)
                        .list(Projections.constructor(UserDto.class,
                                QUser.user.id, QUser.user.username, Expressions.stringTemplate("''"), QUser.user.tenantId,
                                QUser.user.fullname, QUser.user.active, QUser.user.localeKey, GroupBy.set(perm))));

И это намного приятнее, чем версия JPQL / Hibernate-ResultTransformer.

...