I can't find the mistake in my code. Looking for help. Why does the method findById()
return no such object with this id but findAll()
displays this object with this id?
This is my class User
:
@Entity
@Table(name = "users")
public class User {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "login")
private String login;
@Column(name = "password")
private String password;
@JsonIgnore
@OneToOne(optional = false, mappedBy = "user")
private UserDetails userDetails;
}
My class UserDetails
:
@Entity
@Table(name = "userdetails")
public class UserDetails {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "surname")
private String surname;
@OneToOne(optional = false, cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
My controller:
@RestController
public class AnotherUserController {
private final UserRepository userRepository;
@Autowired
public AnotherUserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/demo/{id}")
public User findById(@PathVariable("id") Long id) {
return userRepository.findById(id).orElseThrow(() -> new RuntimeException("user not found: " + id));
}
@PostMapping("/demo")
public User save(@RequestBody User user) {
return userRepository.save(user);
}
@GetMapping("/demo")
public Iterable<User> save() {
return userRepository.findAll();
}
}
My repository:
public interface UserRepository extends CrudRepository<User, Long> {
}
And logs:
2020-07-05 22:11:30.642 ERROR 13200 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed; nested exception is java.lang.RuntimeException: user not found: 23] with root cause
java.lang.RuntimeException: user not found: 23
...
..
.
Ok, so you have @OneToOne(optional = false)
relation, and as you said in the comments, this field is a problem. Finding by id does not return users, because hibernate does inner join
to userdetails
, and since there is no matching record - there is no result.
So the fix is simple: if you want your users returned even when they have no relation to details - mark the relation as optional - @OneToOne(optional = true)
. Hibernate will then generate left outer join
instead of inner join
.
If the relation is not optional (from business point of view), then you should not allow such situation to happen that there exists a user without details. Making that check on a database level would be the best (non-null foreign keys etc.).
btw findAll
returns results, because it translates to select * from users
(no joins) and then fetches details lazily if needed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With