Spring Data JPA - Query via Specification - ManyToMany and Join with Multiple Entities

0

Hello, I've assembled the following class Specification:

public class ItemVendedorSpecification implements Specification<ItemVendedor> {

    private static final long serialVersionUID = 1L;

    @Autowired
    CategoriaRepository categoriaRepository;

    @Autowired
    FabricanteRepository fabricanteRepository;

    @Autowired
    VendedorRepository vendedorRepository;

    private String descricao;

    private List<Long> categorias;
    private List<Long> fabricantes;
    private List<Long> vendedores;

    List<Predicate> predicates = new ArrayList<>();

    public ItemVendedorSpecification(String descricao, List<Long> categorias, List<Long> fabricantes, List<Long> vendedores) {
        super();
        this.descricao = descricao;
        this.categorias = categorias;
        this.fabricantes = fabricantes;
        this.vendedores = vendedores;
    }

    @Override
    public Predicate toPredicate(Root<ItemVendedor> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

        if (!descricao.isEmpty()) {
            String PalavraChave[] = descricao.split(" ");
            for (String filtro : PalavraChave) {
                predicates.add(builder.like(builder.upper(root.get("id").get("produto").get("descricaoDetalhada")), "%" + filtro.toUpperCase() + "%"));
            }
        }

        predicates.add(builder.isTrue(root.get("disponivel")));

        if(!fabricantes.isEmpty()) {
            predicates.add(root.get("id").get("produto").get("fabricante").get("id").in(fabricantes));
        }

        if(!vendedores.isEmpty()) {
            predicates.add(root.get("id").get("vendedor").get("id").in(vendedores));

        }

        if(!categorias.isEmpty()) {
            predicates.add(root.join("id").get("produto").get("categorias").get("id").in(categorias));
        }

        return builder.and(predicates.toArray(new Predicate[1]));
    }
}

Almost all of the predicates are working, except the one that inserts the category criteria. It's not working and I'm having a hard time creating it.

In the way that it is returning the following error:

"Illegal attempt to dereference path source [null.produto.categorias] of basic type; nested exception is java.lang.IllegalStateException: Illegal attempt to dereference path source [null.produto.categorias] of basic type",

Can anyone help me in developing this if?

Below the detail of the ItemSeller class:

public class ItemVendedor implements Serializable{

    private static final long serialVersionUID = 1L;


    private ItemVendedorPK id = new ItemVendedorPK();
    private BigDecimal preco;
    private Boolean disponivel;
    private Date dt_insert;
    private Date dt_update;
    private BigDecimal desconto;

    public ItemVendedor() {

    }

    public ItemVendedor(Produto produto, Vendedor vendedor, BigDecimal preco, BigDecimal desconto ,Boolean disponivel) {
        super();
        this.id.setProduto(produto);
        this.id.setVendedor(vendedor);
        this.preco = preco;
        this.disponivel = disponivel;
        this.desconto = desconto;
    }

//GETs and SETs

As you can see, it has a field called id that is a key made up of the Vendedor vendedor and Produto produto fields.

Within the Product class I have a List<Categoria> categorias . Because a product can belong to several categories.

In turn, the Category class has id .

What I want to put in Specification , is a way to search all ItemVendedor that have within their list of categories some category that I quoted as a parameter in another list List<Long> categorias .

Personal, I am putting some more information to simplify understanding, below is a simplified class diagram to understand the context of the situation:

As you can see in the Product class a product can have several categories, and one category may have several products.

What I intend to do is the following: I want to give a list of values of type Long that refer to category codes. This parameter is passed through a list ( List<Long> categoriasId ) and will be used in the following query:

I want you to return all objects of type Vendor, where the list of product categories has at least 1 item that is within the last parameter list.

This approach is being done through Specification because it is a dynamic query, which will aggregate other criteria according to the class code.

Sincerely.

    
asked by anonymous 22.05.2018 / 16:01

1 answer

1

I managed to resolve. I was using the query in the wrong way. Below is the code for resolution:

predicates.add(root.join("id").join("produto").join("categorias").get("id").in(categorias));

In order to verify that the product had some category that was within the parameter, it was necessary to perform some joins.

The first Join is in relation to what in class code this is as id, this field in the ItemSeller table is actually a class for composite key ( @Embeddable ), in turn this class had to perform the join with the class of Products, which had the Categories field.

So we can get to the list of categories of each product and thus buy if we have any element of this list within the informed query parameter.

    
23.05.2018 / 08:45