I have the following two entities:
@Entity
@Table(name = "organization")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Organization {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
Long id;
@Column(name = "name")
String name;
@OneToMany(mappedBy = "organization")
Set<Team> teams;
}
@Entity
@Table(name = "team")
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
Long id;
@Column(name = "name")
String name;
@Column(name = "description")
String description;
@ManyToOne
@JoinColumn(name="organization_id", nullable=false)
Organization organization;
}
And the following two repositories for those entities
@Repository
public interface OrganizationRepo extends CrudRepository<Organization, Long> {
}
@Repository
public interface TeamRepo extends CrudRepository<Team, Long> {
Optional<Set<Team>> findByOrganizationId(Long organizationId);
Optional<Team> findByOrganizationIdAndTeamId(Long organizationId, Long teamId);
}
I then try to use the findByOrganizationId(..)
method with an organizationId which does not exist, and want it to return an empty optional, but instead I get a HashSet<> with 0 items? Is there a way that I can accomplish this functionality with a JPA method?
@Autowired
TeamRepo repository;
@ResponseBody
@GetMapping(value = "/api/v1/organization/{organizationId}/team")
ResponseEntity<Iterable<Team>> index(@PathVariable Long organizationId) {
Optional<Set<Team>> result = repository.findByOrganizationId(organizationId);
if(result.isPresent()) {
return new ResponseEntity<>(result.get(), HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Edit:
As Organization
to Teams
is a OneToMany relationship, it is reasonable that if there is no Organization
, it should return an empty Optional<>
, but if there is an Organization
with 0 or more teams, it should return an Optional<>
with a Set<>
of zero or more teams.
CodePudding user response:
When you use collections as results you don't need to wrap it in Optional, you can check the collection directly with isEmpty() method:
@Repository
public interface TeamRepo extends CrudRepository<Team, Long> {
Set<Team> findByOrganizationId(Long organizationId);
Optional<Team> findByOrganizationIdAndTeamId(Long organizationId, Long teamId);
}
@Autowired
TeamRepo repository;
@ResponseBody
@GetMapping(value = "/api/v1/organization/{organizationId}/team")
ResponseEntity<Iterable<Team>> index(@PathVariable Long organizationId) {
Set<Team> result = repository.findByOrganizationId(organizationId);
if(!result.isEmpty()) {
return new ResponseEntity<>(result, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
Effective Java book states that: Container types, including collections, maps, streams, arrays, and optionals should not be wrapped in optionals.