For example, when an entity Person which has a @ManyToOne relationship to Company (not cascade) is received for saving, should I manually call companyService.findById() to check that it exists before saving the Person entity?
It is just a matter of protection because if I do not check it and the company does not exists, the person entity will not be persisted (at least in my tests)
What's the best practice for this? I would like to avoid always fetching before saving, and even more if it is a bulk create of persons where the Person entity contains multiple Many to One relationships.
I leave you a simple piece of code.
@Data
@Entity
@Table(name = "person")
public class PersonEntity{
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID uuid;
private String name;
@ManyToOne
@JoinColumn(name = "company_id")
private CompanyEntity company;
@ManyToOne
@JoinColumn(name = "other_entity_id")
private OtherEntity otherEntity;
}
For example, when an entity Person which has a @ManyToOne relationship to Company (not cascade) is received for saving, should I manually call companyService.findById() to check that it exists before saving the Person entity?
It is just a matter of protection because if I do not check it and the company does not exists, the person entity will not be persisted (at least in my tests)
What's the best practice for this? I would like to avoid always fetching before saving, and even more if it is a bulk create of persons where the Person entity contains multiple Many to One relationships.
I leave you a simple piece of code.
@Data
@Entity
@Table(name = "person")
public class PersonEntity{
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID uuid;
private String name;
@ManyToOne
@JoinColumn(name = "company_id")
private CompanyEntity company;
@ManyToOne
@JoinColumn(name = "other_entity_id")
private OtherEntity otherEntity;
}
Share
Improve this question
edited Mar 22 at 14:09
Vishal
1,4163 gold badges14 silver badges30 bronze badges
asked Mar 22 at 1:37
EvoldevEvoldev
356 bronze badges
2 Answers
Reset to default 1When 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.
It depends. Since this is an opinion-based question, here are my two cents.
If a "company" doesn't exist and there's nothing to do about it - no eligibility checks, no need to verify associations - I'd leave it as is. This is often the case for entities like addresses. There will only be an issue if there's a bug that sends an incorrect ID. If not, it's likely someone tampering with the request, and we don’t need to entertain them with a proper validation message. I assume this applies to your case since you can opt out of fetching the entity (JpaRepository#getReferenceById
).
If validation is necessary, like for eligibility checks, logging, or ensuring associations are intact, I'd implement some sort of caching mechanism.