When you dealing with the tag @ManyToOne you can rely on the "database" constrain, the id of the entity.
If you concerned on the Bulk operation, there is Optimization you can do. You can optimize by fetching all referenced entities in a single query before performing the bulk save. This reduces the number of database queries (related to the reference entity).
public void savePersons(List<PersonEntity> persons) {
// getting all the company id
Set<UUID> companyIds = persons.stream()
.map(PersonEntity::getCompany)
.filter(Objects::nonNull)
.map(CompanyEntity::getId)
.collect(Collectors.toSet());
// find to db the reference of company that
// will be used in Person entity. And build as map (for efficient check exists by id)
Map<UUID, CompanyEntity> companies = companyService.findAllById(companyIds).stream()
.collect(Collectors.toMap(CompanyEntity::getId, Function.identity()));
for (PersonEntity person : persons) {
if (
person.getCompany() != null &&
// check the company reference id is find in Map(from db)
!companies.containsKey(person.getCompany().getId())
) {
// you can either skip/remove the person or throw error like this
throw new EntityNotFoundException("Company not found for person: " + person.getName());
}
}
personRepository.saveAll(persons);
}
Pros: More efficient than checking each entity individually in bulk operations. Cons: Requires more complex logic to handle the fetching and mapping of referenced entities.