Nadpisywanie wartości w bazie danych

0

Cześć! Tak jak w temacie - borykam się z problemem nadpisywania wartości w mojej bazie danych. Projekcik jest skromny, wykonany w springu. Dwie encje - User i Book. Zależność @OneToMany. Klucz obcy user_id. Teraz schemacik: strona startowa to lista wszystkich użytkowników, na niej mam przycisk dodania nowego użytkownika. Po jego stworzeniu mogę do każdego przypisać książkę. Klikam w przycisk "Add book" przy użytkowniku dajmy na to o Id=1, wyświetlany jest formularz do stworzenia ksiazki (pola tytul, autor) a nastepnie ksiazka ląduje do bazy danych a widok przeskakuje znowu do listy użytkowników. I teraz mój problem - jeśli znowu wybiorę użytkownika od Id=1 czyli klucz obcy dla nowej książki będzie taki sam jak dla poprzednio stworzonej książki to poprzednia książka zostanie nadpisana w bazie. To samo tyczy się oczywiście użytkowników o innych Id ;) Nie wiem gdzie może błąd występować, jeśli kod do wglądu jest potrzebny to proszę o napisanie, którą warstwę udostępnić (kontroler, widok) to edytuję post :) Będę wdzięczny za każdą pomoc :P

@PostMapping("/user/{id}/saveBook")
    public String saveBook(@ModelAttribute Book book, @PathVariable("id") Long id) {

        User user = userService.findById(id);
        book.setUser(user);
        bookService.saveBook(book);

        return "redirect:/user/list";
    }

    @GetMapping("/user/{id}/new")
    public String showAddBookForm(Model model, @PathVariable("id") Long id, User user){

        Book book = new Book();
        model.addAttribute("book", book);
        model.addAttribute("user", user);

        return "book-form";
    }
```java

Templatka book-form:
```html
<form th:object="${book}"  th:action="@{'/user/' + ${user.id} + '/saveBook'}" method="post">
        <table>
            <tr>
                <input type="text" th:field="*{title}" placeholder="Title" />
                <input type="text" th:field="*{author}" placeholder="Author" />
                <select class="form-control" th:field="*{bookCategory}">
                    <option th:each="category : ${T(com.skoczek.demo.model.BookCategory).values()}"
                            th:value="${category.name()}"
                            th:text="${category.name()}"
                            >val</option>
                </select>
            </tr>
            <button type="submit">Save</button>
        </table>
    </form>
```html
0

Nie jestem na tyle doświadczoną osobą, żeby Ci powiedzieć dlaczego tak się dzieję (radziłbym Ci w debuggerze zobaczyć czy jak podajesz id usera to czy przypadkiem książka Ci się automatycznie nie mapuje na to samo id, pewnie podajesz id użytkownika rowne 1).

Troche masz bałagan w kodzie, ja bym to zrobił tak:

@GetMapping("/user/{id}/new-book")
    public String showAddBookForm(Model model, @PathVariable("id") Long id){
        User user = userService.findById(id);
        Book book = new Book(user);
        model.addAttribute("book", book);
        return "book-form";
    }
@PostMapping("/user/{id}/new-book")
    public String saveBook(@ModelAttribute Book book) {
        bookService.saveBook(book);
        return "redirect:/user/list";
    }

nie musisz zmieniać url, wystarczą adnotacje getmapping i postmapping, nie musisz tez dodawać do model attribute usera jak nastepnie go pozyskujesz w poscie, wystarczy wyslac ksiazke z wypelnionym polem User user (pamietaj tylko ze musisz do widoku dodac ukryte pole typu user, aby go nie zbubić wysyłając ksiazke z powrotem do kontrolera)

Alternatywnie mozesz w getcie stworzyc booka bez usera i w poscie zlapac id ktore później dodasz do booka

@GetMapping("/user/{id}/new-book")
    public String showAddBookForm(Model model){
        Book book = new Book();
        model.addAttribute("book", book);
        return "book-form";
    }
@PostMapping("/user/{id}/new-book")
    public String saveBook(@ModelAttribute Book book, @PathVariable Long id) {
        User user = userService.findById(id);
        book.setUser(user);
        bookService.saveBook(book);
        return "redirect:/user/list";
    }
0

Gdy dodaję ukryte pole typu user to dostaję taki błąd:

Field error in object 'book' on field 'user': rejected value [com.skoczek.demo.model.User@6787c455]; codes [typeMismatch.book.user,typeMismatch.user,typeMismatch.com.skoczek.demo.model.User,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [book.user,user]; arguments []; default message [user]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'com.skoczek.demo.model.User' for property 'user'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.skoczek.demo.model.User' for property 'user': no matching editors or conversion strategy found]]

Mój widok:

<form th:object="${book}"  th:action="@{'/user/' +${book.user.id} + '/new-book'}" method="post">
        <table>
            <tr>
                <input type="hidden" th:field="*{user}" />
                <input type="text" th:field="*{title}" placeholder="Title" />
                <input type="text" th:field="*{author}" placeholder="Author" />
                <select class="form-control" th:field="*{bookCategory}">
                    <option th:each="category : ${T(com.skoczek.demo.model.BookCategory).values()}"
                            th:value="${category.name()}"
                            th:text="${category.name()}"
                            >val</option>
                </select>
            </tr>
            <button type="submit">Save</button>
        </table>
    </form>
0

Dlatego lepiej skorzystaj z drugiego rozwiązania, w którym nie musisz miec ukrytego pola user (tutaj zmiast user polecałbym trzymanie user_id, spring powinien sobie poradzic z zmapowaniem go na usera)

0

Tylko teraz pojawia się problem jak przesłać id mojego usera w miejsce pytajników tak aby móc złapać go w poscie :/

<form th:object="${book}"  th:action="@{'/user/' +${??????????} + '/new-book'}" method="post">
0

Pokaż klasę Book. User w sumie też.

0

Okej, problem zażegnany, udało się :D Dzięki @Kubańczyk i wszystkim którzy chcieli pomóc ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1