Problema ao executar duas consultas JPA da mesma entidade

Estou fazendo uma consulta para buscar a cidade selecionada e o bairro selecionado pelo usuario. Podem ocorrer duas situações:

  1. Buscar apenas um bairro, que seria o local de entrega

  2. Buscar dois bairros, que seria o local de entrega e o local de cobrança

Quando faço apenas uma busca, os dados retornados são os esperados.
Quando as cidades são diferentes a query retorna os dados esperados.
Porém se eu tenho duas buscas (cobrança e entrega) na mesma cidade não retorna o esperado.

A seguir o código que verifico se tenho o endereço de entrega e cobrança e faço as consultas no BD

       // se tiver o endereço de cobrança
       if(viewSearchShipping.getIdBilling()>0){
            // procuro o endereco do cliente no BD
            AddressBook addressBook = addressBookService.findById(viewSearchShipping.getIdBilling());
            //procuro no BD a cidade e bairros que a empresa atende
            CityShipping cityShipping = cityShippingService.findByName(addressBook.getCity());
            
            // aqui removo os bairros que não importam para cotar o frete, ou seja deixo apenas o bairro que o cliente selecionou
            cityShipping.getDistrictShipping().removeIf(disct -> !disct.getName().equalsIgnoreCase(addressBook.getDistrict()));
            // e adiciono numa lista que sera o retorno no final do codigo para poder cotar o frete total
            shippingList.add(cityShipping);
        }
        // endereço de entrega
        if(viewSearchShipping.getIdShipping()>0){
            AddressBook addressBook = addressBookService.findById(viewSearchShipping.getIdShipping());
            CityShipping cityShipping = cityShippingService.findByName2(addressBook.getCity());
            
            cityShipping.getDistrictShipping().removeIf(disct -> !disct.getName().equalsIgnoreCase(addressBook.getDistrict()));

            shippingList.add(cityShipping);
        }

OBS.: Como sou novo no forum só posso postar uma foto, então uni as duas fotos em uma.

Na imagem 1 demonstro o que retorna na primeira consulta (retorna o esperado)
O bairro procurado era “Costa e Silva”. No método shippingList.add(cityShipping); o retornado seria a cidade e o bairro “Costa e Silva”.

Na imagem 2 demonstro o que retorna na segunda consulta
E aqui que acontece o estranho, deveria retornar igual a imagem 1, a cidade com seus 3 bairros atendidos porém retorna o bairro “Costa e Silva”. Isso que não entendo do por que o retorno do bairro Costa e silva se executo a mesma query com a mesma cidade.

Meu Service é esse:

@Override
public CityShipping findByName(String name) {
    return cityShippingRepository.findByNameAndActiveAndExcluded(name, true, false);
}

Meu repositório:

CityShipping findByNameAndActiveAndExcluded(String name, boolean active, boolean excluded);

Desde já agradeço pela ajuda!

Pode ser que o resultado desse método esteja sendo compartilhado entre as duas consultas.
Então se removeu na primeira, remove na segunda também.

Dentro desse método você poderia retornar uma coleção nova.

@RoinujNosde Desconfio disso também, mas não entendi a sua solução, você diz em dentro da minha classe CityShipping aonde faço o getDistrictShipping() retornar uma nova List ?

public List<DistrictShipping> getDistrictShipping() {
     return this.districtShipping;
}

Isso.

return new ArrayList<>(districtShipping);

Funcionou, porém o método .removeIf() que uso para retirar os bairros que não desejo não funciona mais, ele não removem nenhum bairro.

Onde você vai usar os bairros restantes? Mostra o código.

Então, quando a consulta retorna a cidade e os bairros atendidos quero remover o bairro que não for igual ao selecionado no front, por isso faço um removeIf dos bairros que tem o nome diferente daquele selecionado. Após a remoção retorno os dados para o front para fazer a soma dos valores do bairros para ter o total da entrega.
O código completo é:

@PostMapping("findShipping/")
public ResponseEntity<?> findShipping (@RequestBody ViewSearchShipping viewSearchShipping, BindingResult bindingResult) {
    AjaxResponse result = new AjaxResponse();
    //lista para retorno 
    List<CityShipping> shippingList = new ArrayList<CityShipping>();

    if(viewSearchShipping.getIdCustomer()>0) {
        //endereço de cobrança
        if(viewSearchShipping.getIdBilling()>0){
            AddressBook addressBook = addressBookService.findById(viewSearchShipping.getIdBilling());
            CityShipping cityShipping = cityShippingService.findByName(addressBook.getCity());
            //removo os bairros e deixo apenas o selecionado no front
            cityShipping.getDistrictShipping().removeIf(disct -> !disct.getName().equalsIgnoreCase(addressBook.getDistrict()));

            shippingList.add(cityShipping);
        }
        //endereço de entrega
        if(viewSearchShipping.getIdShipping()>0){
            AddressBook addressBook = addressBookService.findById(viewSearchShipping.getIdShipping());
            CityShipping cityShipping = cityShippingService.findByName(addressBook.getCity());
            //removo os bairros e deixo apenas o selecionado no front
            cityShipping.getDistrictShipping().removeIf(disct -> !disct.getName().equalsIgnoreCase(addressBook.getDistrict()));

            shippingList.add(cityShipping);
        }
    }

    if(shippingList.size()>0){
        return ResponseEntity.ok(shippingList);
    }else{
        result.setMsg("Não encontramos um frete para esta região");
        return ResponseEntity.badRequest().body(result);
    }
}

Essa classe CityShipping tem um método setDistrictShipping?

Mostra o código dessa classe.

@Entity
@Table(name="city_shipping")
public class CityShipping {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private long id;

@OneToMany(mappedBy = "cityShipping", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<DistrictShipping> districtShipping;

@Column
@NotEmpty(message = "Campo Obrigatório")
private String name;

@Column
private BigDecimal valueCar;

@Column
private BigDecimal valueMotorcycle;

@Column
private boolean active = false;

@Column
private boolean excluded = false;

public long getId() {
	return this.id;
}

public void setId(long id) {
	this.id = id;
}

public List<DistrictShipping> getDistrictShipping() {
	return new ArrayList<DistrictShipping>(districtShipping);
}

public void setDistrictShipping(List<DistrictShipping> districtShipping) {
	this.districtShipping = districtShipping;
}

public String getName() {
	return this.name;
}

public void setName(String name) {
	this.name = name;
}

public BigDecimal getValueCar() {
	return this.valueCar;
}

public void setValueCar(BigDecimal valueCar) {
	this.valueCar = valueCar;
}

public BigDecimal getValueMotorcycle() {
	return this.valueMotorcycle;
}

public void setValueMotorcycle(BigDecimal valueMotorcycle) {
	this.valueMotorcycle = valueMotorcycle;
}

public boolean isActive() {
	return this.active;
}

public void setActive(boolean active) {
	this.active = active;
}

public boolean isExcluded() {
	return this.excluded;
}

public void setExcluded(boolean excluded) {
	this.excluded = excluded;
}

}

Bom, desfaça aquela alteração no método getDistrictShipping e implemente a interface Cloneable.

@Entity
@Table(name = "city_shipping")
public class CityShipping implements Cloneable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private long id;

    @OneToMany(mappedBy = "cityShipping", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<DistrictShipping> districtShipping;

    @Column
    @NotEmpty(message = "Campo Obrigatório")
    private String name;

    @Column
    private BigDecimal valueCar;

    @Column
    private BigDecimal valueMotorcycle;

    @Column
    private boolean active = false;

    @Column
    private boolean excluded = false;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public List<DistrictShipping> getDistrictShipping() {
        return districtShipping;
    }

    public void setDistrictShipping(List<DistrictShipping> districtShipping) {
        this.districtShipping = districtShipping;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getValueCar() {
        return this.valueCar;
    }

    public void setValueCar(BigDecimal valueCar) {
        this.valueCar = valueCar;
    }

    public BigDecimal getValueMotorcycle() {
        return this.valueMotorcycle;
    }

    public void setValueMotorcycle(BigDecimal valueMotorcycle) {
        this.valueMotorcycle = valueMotorcycle;
    }

    public boolean isActive() {
        return this.active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public boolean isExcluded() {
        return this.excluded;
    }

    public void setExcluded(boolean excluded) {
        this.excluded = excluded;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        CityShipping clone = (CityShipping) super.clone();
        clone.setDistrictShipping(new ArrayList<>(districtShipping));

        return clone;
    }

}

No método clone() ele vai criar um objeto novo e também uma nova lista dos distritos, resolvendo o problema de modificar o mesmo objeto.

E para usar vc faz:

cityShippingService.findByName(addressBook.getCity()).clone();
1 curtida

Certo, o método Clone() ao inves de retornar um Object não deveria seria ser CityShipping, ficando assim:

Outra questão é ao chamar o método ficou assim:

CityShipping cityShipping = cityShippingService.findByName(addressBook.getCity()).clone();

E o seguinte erro acontece:

The method clone() from the type CityShipping is not visibleJava(67108965)

O método clone() tem que ser protected mesmo? ou pode ser public?

Agradeço sua ajuda!

Opa, erro meu.
Fiz rapidinho no bloco de notas.

Isso, tem que ser public e retornar o CityShipping.

1 curtida

Muito Obrigado, resolveu meu problema!
Agradeço!!

1 curtida