Rest API Spring + ORM - niespójne modele danych

Rest API Spring + ORM - niespójne modele danych
Pangeon
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Łódź
  • Postów:163
0

Witam, pracuje nad aplikacją. Problem mam złożony więc postaram się bardziej ogólnie. Model danych w relacyjnej bazie jest niespójny z obiektowym modelem danych. Nie mogę obsłużyć na poziomie REST API relacji @ManyToOne. Niby wszystko wydaje się okej, póki nie próbuje uzyskać kolekcji, gdzie tworzy mi się nieskończony ciąg wywołań, gdyż podczas mapowania posłużyłem się referencją do obiektu, która posiada kolekcję...

Owner

Kopiuj
@Entity
@Table(name = "OWNER")
public class Owner implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Integer id;

    @OneToMany(mappedBy = "ownerId",
            fetch = FetchType.EAGER,
            cascade = CascadeType.ALL)
    private List<Payments> payments;

Payment

Kopiuj
@Entity
@Table(name = "PAYMENTS")
public class Payments implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Integer id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "OWNER_ID",
            foreignKey=@ForeignKey(name="OWNER_ID"),
            nullable = true) // TO FIXED: tymczasowe usunięcie ograniczenia z bazy danych
    private Owner ownerId;

Chciałbym móc dodawać do tabeli klucze obce, móc powiązać płatność z jej posiadaczem. Na razie działa mi to tylko częściowo.

Kopiuj
@PostMapping("/insert")
    void insertOwner(@RequestBody Payments body) {
        message.getInfo("insertPayment()", body);
        body.setDate(new Timestamp(System.currentTimeMillis()));
        paymentsRepository.save(body);
    }

Płatność mogę dodać ale nie mogę wskazać na relację klucz obcy bo przy budowania ORM-a posłużyłem się obiektem, w tej sytuacji wystarczyłoby przekazanie liczby ale się nie da. Obsłużyłem co prawda dodanie płatności do tabeli z kluczem obcym ale tym działaniem popsuła mi się metody do wywoływania kolekcji, bo wszystko się zapętla.

Kopiuj
* owner

        +---------+---------+------+-----+---------+----------------+
        | Field   | Type    | Null | Key | Default | Extra          |
        +---------+---------+------+-----+---------+----------------+
        | id      | int(11) | NO   | PRI | NULL    | auto_increment |
        | name    | text    | NO   |     | NULL    |                |
        | surname | text    | NO   |     | NULL    |                |
        +---------+---------+------+-----+---------+----------------+
        
* payments

       +----------+-----------+------+-----+-------------------+-------------------+
        | Field    | Type      | Null | Key | Default           | Extra             |
        +----------+-----------+------+-----+-------------------+-------------------+
        | id       | int(11)   | NO   | PRI | NULL              | auto_increment    |
        | amount   | double    | NO   |     | NULL              |                   |
        | date     | timestamp | YES  |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
        | kind     | tinytext  | NO   |     | NULL              |                   |
        | owner_id | int(11)   | YES  | MUL | NULL              |                   |
        +----------+-----------+------+-----+-------------------+-------------------

Proszę o wskazówki


Sukces jest progresywną realizacją wartościowej idei w ramach cierpliwego wymiaru czasu.
edytowany 3x, ostatnio: Pangeon
E9
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Postów:216
1

Dodaj

Kopiuj
@JsonManagedReference
@OneToMany

i

Kopiuj
@JsonBackReference
@ManyToOne
edytowany 3x, ostatnio: Emdzej93
Pangeon
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Łódź
  • Postów:163
0

Dziękuje to rozwiązanie działa na tym etapie produkcji mnie zadowala. Nie da się konstruktora zrobić w klasie @Entity i nie widać tych kluczy obcych w tym co zwraca kontroler ale dane się zapisują na poziomie tabeli.

Kopiuj
@PostMapping("/insert/{id}")
    void insertOwner(@RequestBody Payments body, @PathVariable Integer id) {
        message.getInfo("insertPayment()", body);
        Owner owner = new Owner();
        owner.setId(id);
        body.setOwnerId(owner);
        body.setDate(new Timestamp(System.currentTimeMillis()));
        paymentsRepository.save(body);
    }
``` 
Gratuluje intuicji :) bo w zasadzie przedstawiłem tylko zarys tego co chce zrobić.

Sukces jest progresywną realizacją wartościowej idei w ramach cierpliwego wymiaru czasu.
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:około 18 godzin
  • Postów:1875
0

Nie, nie, nie. Dlaczego pchasz model bazy danych przez Resta? W ten sposób upubliczniłeś swój wewnętrzny model i nie jesteś go w stanie łatwo zmienić w razie potrzeby. Osobna klasa na encję JPA i osobna na jsona.


”Engineering is easy. People are hard.” Bill Coughran
DW
  • Rejestracja:ponad 5 lat
  • Ostatnio:około 3 godziny
  • Postów:64
1

Jeszcze lepszym pomysłem będzie skorzystanie z adnotacji @JsonIgnore, którą umieścisz po stronie ChildEntity (Payments w Twoim przypadku, pole ownerId).
Poniżej link ze świetnym wyjaśnieniem.
https://stackoverflow.com/a/37394318
PS: Uniezależnij model od twojego Rest API, przyjmuj Dto oraz zwracaj Dto.

edytowany 1x, ostatnio: dawid.wiklo4
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Silesia/Marki
  • Postów:5505
2
Charles_Ray napisał(a):

Nie, nie, nie. Dlaczego pchasz model bazy danych przez Resta? W ten sposób upubliczniłeś swój wewnętrzny model i nie jesteś go w stanie łatwo zmienić w razie potrzeby. Osobna klasa na encję JPA i osobna na jsona.

Może tak, może nie.
W niektórych projektach "Encja na twarz i pchasz" jest wystarczającym rozwiązaniem. Np jeśli Encja jest mała. Gdy się rozrośnie zawsze można przerobić Encje na DTO.
Nie bardzo widzę sens w pisaniu nadmiarowych DTO. Przecież to może nigdy się nie przydać. To trochę tak jak robienie interfejsów do wszystkich klas bo może kiedyś będziemy mieć drugą implementację i wtedy będzie łatwiej


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:około 18 godzin
  • Postów:1875
2

To wtedy masz klasy typu:

Kopiuj
@Entity
@JsonCostam
@XmlElement
@Data
public class Person { ... }

Nie wygląda to przystępnie. Jak encja jest mała, to... niedługo może by większa. Przy takim designie łatwo coś zepsuć, muszę pamiętać, że na klasie jest zapięte wiele różnych mechanizmów mapowania. Czy to nie łamie SRP?


”Engineering is easy. People are hard.” Bill Coughran
Shalom
annotation driven development :D
Pangeon
  • Rejestracja:prawie 10 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Łódź
  • Postów:163
0

To taka bardzo akademicka aplikacja, bez skomplikowanego modelu danych aby pokazać wszystkie poziomy dojrzałości REST API. Jak zawsze podszedłem ambitniej więc myślę musi być także baza oraz widok, bo samo API to nie aplikacja. Przydadzą mi się informacje teoretyczne odnośnie wzorców, bo w zasadzie chodzi o to by pokazać jak robić dobrze przy większych projektach także. DTO warte jest uwagi z poziomu użyteczności API. Uparłem się na dane i mam więcej roboty, a przecież sam opis tworzenia kontrolera można zrobić na wiele rozdziałów. Aplikacja przyda mi się jako wzór, nie chodzi mi o 5+ robię to dla siebie.

Dziękuje za pomoc.


Sukces jest progresywną realizacją wartościowej idei w ramach cierpliwego wymiaru czasu.
edytowany 2x, ostatnio: Pangeon

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.