Mam w sumie dwa pytania, jedno dotyczy samego błędu który się pojawił, a drugie designu tej encji. Zacznijmy od samego błędu, mam taką encje
@Entity
@Data
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String password;
private String firstName;
private String lastName;
@ManyToMany
private List<Person> friends = new ArrayList<>();
@OneToMany
private List<Post> posts = new ArrayList<>();
}
I taką konfigurację w application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/postgres
username: postgres
password: qwe123
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
W bazie zapisuje kilka osób
@PostConstruct
public void init() {
Person adam = userRepository.save(user("adam"));
Person jan = userRepository.save(user("jan"));
Person anna = userRepository.save(user("anna"));
adam.setFriends(List.of(jan, anna));
jan.setFriends(List.of(adam));
anna.setFriends(List.of(adam));
userRepository.save(adam);
userRepository.save(jan);
userRepository.save(anna);
}
private Person user(String name) {
Person person = new Person();
person.setFirstName(name);
return person;
}
I teraz tak, oczywiście jak wypchnę findAll()
bezpośrednio do controllera, to leci StackOverflow
, przez ManyToMany
na tych encjach. Rozwiązaniem jest zmapowanie tego na DTO. Jeżeli jednak dobrze rozumiem, to wtedy każde query do bazy które zwraca Person
, zwróci również kolekcję friends
oraz posts
. W większości przypadków to nie ma sensu, powiedzmy, że chcę zrobić endpoint typu GET/user/profile
, gdzie zwracam jego dane osobowe i tyle. Oczywiście mogę wyciągnąć z bazy wszystko i zmapować na DTO, ale to raczej słabe rozwiązanie, jeżeli np. dana osoba ma 200 przyjaciół i 1000 postów, które wyciągne tylko po to by wziąć imię i nazwisko tej osoby.
Dopisałem więcj takie coś w repo, oczekując że dostanę Person
z wypełnionym tylko id
, firstName
, lastName
.
public interface PersonRepository extends CrudRepository<Person, Long> {
@Query(
value = "SELECT p.id, p.first_name, p.last_name FROM PERSON p WHERE p.id = ?1",
nativeQuery = true)
Optional<Person> findPersonBasicInformation(Long id);
}
Wygląda jednak na to, że w tym zapytaniu muszę podać wszytkie kolumny, bo leci coś takiego i nie bardzo wiem dlaczego.
org.postgresql.util.PSQLException: The column name email was not found in this ResultSet.
Drugie pytanie, z podstaw relacyjnych baz w sumie... co faktycznie zyskuje używając tutaj relacji między osobami czy osobami a ich postami? Powiedzmy, że chcę wyciągnąć dane posta i podstawowe informację o jego autorze, jaka jest korzyść z zrobienia tutaj relacji między tymi encjami? Mógłbym chyba po prostu wywalić kolekcję posts
z encji Person
, a za to w encji Post
trzymać tylko id autora i zrobić joina który wyciągnie mi dodatkowo np. jego imię i nazwisko.