0

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.

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

5 Comments

I was about to say "but then why does it do it with the original findById(..) method, but then I checked, and it doesn't. So good point, however I want it is representing a OneToMany relationship, and so therefore if there isn't an organization, return empty optional, but if there is an organization return a set with 0 or more items.
based on my understanding you are trying to check if the organization exists with that id before trying to find the Teams of that organization. If this is the case then you need to inject @Autowired OrganizationRepo organizationRepo; in your controller and then call organizationRepo.findById(organizationId) that returns Optional, if that is empty return return new ResponseEntity<>(HttpStatus.NOT_FOUND); otherwise return the result from repository.findByOrganizationId(organizationId)
Right, I know that is a way of doing it I was just wondering if there was a cleaner way of doing it with a single query using JPA Repository Methods.
I don't think there is a cleaner approach, you need to do these two calls.
Ok, cool. I'm going to leave the question up for the weekend and if no one else comes back with any ideas I'll mark this as the answer. Thanks for your quick reply!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.