'How to remove an element from a Set inside a Page of items based on a Condition using Java 8
I have a Page
of Farmers
coming from a JPA repository call findAll
method. Each Farmer consists of a Set
of Farms
which are also coming in the repository call like so:
public class Farmer {
private String name;
@ManyToMany
@JoinTable(name = "farmer_asset", joinColumns = @JoinColumn(name = "farmer_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "asset_id", referencedColumnName = "id"))
private Set<Asset> assets;
}
Asset
has a property called isActive
which indicates that the asset is active or not;
In my Page
of Farmers
I want to select only farmers' Assets which are active;
I tried with
@WhereJoinTable(clause = "is_active ='true'")
However, I learnt that the is_active
property is supposed to be in the intermediate ManyToMany relation Table farmer_asset
Now I am not in a position to change the entity structure, and use @WhereJoinTable(clause = "is_active ='true'")
.
So, I thought of trying to filter the values after making the JPA call.
However, iterating through each Farmer
, then removing the inActive Assets
and then adding it back to the Page and maintaining Page elements seemed too performance heavy operation.
I tried with normal Java Code which looks something like this:
Page<Farmer> farmers = farmerRepository.findAll(pageable);
List<Farmer> farmersList = new LinkedList<>();
for (FarmerDto eachFarmer : farmers.getContent()) {
Set<Asset> eachFarmerAssets =
eachFarmer.getAssets();
eachFarmerAssets.removeIf(e ->
!e.getIsActive());
eachFarmer.setAssets(eachFarmerAssets);
farmersList.add(eachFarmer);
}
return new PageImpl<FarmerDto>(farmersList, pageable, farmers.getTotalElements());
I would like to do this is Java 8 using streams but I am not able to iterate a list and change its element which is in turn a Set<Asset>
Came here looking for some suggestions.
Thanks in advance.
Solution 1:[1]
You actually don't to reassign the same reference to Set<Asset>
because even the set has been modified, it's still the same object which is "known" to a particular farmer.
And definitely you don't need streams for this task. Documentation suggests avoiding stateful operations and side-effects while designing stream pipe-lines.
Instead, you can use forEach()
method on a list:
Page<Farmer> farmers = farmerRepository.findAll(pageable);
List<Farmer> farmersList = new farmers.getContent();
farmersList.forEach(farmer -> farmer.getAssets()
.removeIf(e -> !e.getIsActive()));
Solution 2:[2]
You have to follow these steps:
- retrieve the list of farmer entities
- transform the list of entities to the list of farmer dtos
- for each farmer dto
- fill the data
- put the list of assert that are active
List<Farmer> farmers = farmerRepository.findAll(pageable).getContent(); //1
List<FarmerDto> farmersList = farmers.stream() // 2
.map(farmer -> { // 3
FarmerDto farmerDto = new FarmerDto();
// fill farmerDto 3.1
farmerDto.setAssets(farmer.getAssets().stream().filter(Farmer::getIsActive()).toList()); //3.2
return farmerDto;
}).toList();
return new PageImpl<FarmerDto>(farmersList, pageable, farmers.getTotalElements());
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | frascu |