2017-07-06 4 views
2

Gibt es eine Möglichkeit, Repository Abfrageergebnisse nach querydsl Alias ​​zu sortieren?Wie sortiere ich nach querydsl alias

Bisher habe ich zu filtern geschafft, aber Sortierergebnisse mit einem Fehler:

org.springframework.data.mapping.PropertyReferenceException: No property username found for type User!

Anfrage:

GET /users?size=1&sort=username,desc

meine Ruhe Controller-Methode:

@GetMapping("/users") 
public ListResult<User> getUsersInGroup(
     @ApiIgnore @QuerydslPredicate(root = User.class) Predicate predicate, 
     Pageable pageable) { 
    Page<User> usersInGroup = 
      userRepository.findByGroup(CurrentUser.getGroup(), predicate, pageable); 
    return new ListResult<>(usersInGroup); 
} 

mein Repository:

@Override 
default void customize(QuerydslBindings bindings, QUser root) { 
    bindings.including(root.account.login, root.account.firstName, root.account.lastName, 
      root.account.phoneNumber, root.account.email, root.account.postalCode, root.account.city, 
      root.account.address, root.account.language, root.account.presentationAlias); 
    bindAlias(bindings, root.account.login, "username"); 
} 

default Page<User> findByGroup(Group group, Predicate predicate, Pageable pageable) { 
    BooleanExpression byGroup = QUser.user.group.eq(group); 
    BooleanExpression finalPredicate = byGroup.and(predicate); 
    return findAll(finalPredicate, pageable); 
} 

default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) { 
    bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase); 
} 

Ich habe auch versucht PageableArgumentResolver meine eigenen zu implementieren, basierend auf QuerydslPredicateArgumentResolver, aber einige der Methoden gibt es Paket privat so dachte ich, vielleicht ich in der falschen Richtung gehe

Antwort

2

ich gelungen, indem a PageableArgumentResolver mit dem Klassentyp der Abfrage-Stammklasse annotiert und der generischen Repository-Schnittstelle eine Alias-Registrierung hinzugefügt.

Diese Lösung scheint, wie dieses Problem zu umgehen, aber zumindest funktioniert es;)

Repository:

public interface UserRepository extends PageableAndFilterableGenericRepository<User, QUser> { 

QDSLAliasRegistry aliasRegistry = QDSLAliasRegistry.instance(); 

@Override 
default void customize(QuerydslBindings bindings, QUser root) { 
    bindAlias(bindings, root.account.login, "username"); 
} 

default void bindAlias(QuerydslBindings bindings, StringPath path, String alias) { 
    bindings.bind(path).as(alias).first(StringExpression::likeIgnoreCase); 
    aliasRegistry.register(alias, path); 
} 

alias Registrierung:

public class QDSLAliasRegistry { 

private static QDSLAliasRegistry inst; 

public static QDSLAliasRegistry instance() { 
    inst = inst == null ? new QDSLAliasRegistry() : inst; 
    return inst; 
} 

private QDSLAliasRegistry() { 
    registry = HashBiMap.create(); 
} 

HashBiMap<String, Path<?>> registry; 

Resolver:

public class QDSLSafePageResolver implements PageableArgumentResolver { 

private static final String DEFAULT_PAGE = "0"; 
private static final String DEFAULT_PAGE_SIZE = "20"; 
private static final String PAGE_PARAM = "page"; 
private static final String SIZE_PARAM = "size"; 
private static final String SORT_PARAM = "sort"; 
private final QDSLAliasRegistry aliasRegistry; 

public QDSLSafePageResolver(QDSLAliasRegistry aliasRegistry) { 
    this.aliasRegistry = aliasRegistry; 
} 

@Override 
public boolean supportsParameter(MethodParameter parameter) { 
    return Pageable.class.equals(parameter.getParameterType()) 
      && parameter.hasParameterAnnotation(QDSLPageable.class); 
} 

@Override 
public Pageable resolveArgument(MethodParameter parameter, 
           ModelAndViewContainer mavContainer, 
           NativeWebRequest webRequest, 
           WebDataBinderFactory binderFactory) { 

    MultiValueMap<String, String> parameterMap = getParameterMap(webRequest); 

    final Class<?> root = parameter.getParameterAnnotation(QDSLPageable.class).root(); 
    final ClassTypeInformation<?> typeInformation = ClassTypeInformation.from(root); 

    String pageStr = Optional.ofNullable(parameterMap.getFirst(PAGE_PARAM)).orElse(DEFAULT_PAGE); 
    String sizeStr = Optional.ofNullable(parameterMap.getFirst(SIZE_PARAM)).orElse(DEFAULT_PAGE_SIZE); 
    int page = Integer.parseInt(pageStr); 
    int size = Integer.parseInt(sizeStr); 
    List<String> sortStrings = parameterMap.get(SORT_PARAM); 
    if(sortStrings != null) { 
     OrderSpecifier[] specifiers = new OrderSpecifier[sortStrings.size()]; 

     for(int i = 0; i < sortStrings.size(); i++) { 
      String sort = sortStrings.get(i); 
      String[] orderArr = sort.split(","); 
      Order order = orderArr.length == 1 ? Order.ASC : Order.valueOf(orderArr[1].toUpperCase()); 
      specifiers[i] = buildOrderSpecifier(orderArr[0], order, typeInformation); 
     } 

     return new QPageRequest(page, size, specifiers); 
    } else { 
     return new QPageRequest(page, size); 
    } 
} 

private MultiValueMap<String, String> getParameterMap(NativeWebRequest webRequest) { 
    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>(); 

    for (Map.Entry<String, String[]> entry : webRequest.getParameterMap().entrySet()) { 
     parameters.put(entry.getKey(), Arrays.asList(entry.getValue())); 
    } 
    return parameters; 
} 

private OrderSpecifier<?> buildOrderSpecifier(String sort, 
               Order order, 
               ClassTypeInformation<?> typeInfo) { 


    Expression<?> sortPropertyExpression = new PathBuilderFactory().create(typeInfo.getType()); 
    String dotPath = aliasRegistry.getDotPath(sort); 
    PropertyPath path = PropertyPath.from(dotPath, typeInfo); 
    sortPropertyExpression = Expressions.path(path.getType(), (Path<?>) sortPropertyExpression, path.toDotPath()); 

    return new OrderSpecifier(order, sortPropertyExpression); 
} 
} 
Verwandte Themen