jpa repository.save 函数更改其子实体的ID

0md85ypi  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(155)

I'm trying to update existing entry in parent Entity and I encounter error I can't understand nor resolve. I have two entities in a simple crud repository - Parent(User) and Children(movie). I am trying to pass a favourite movie to an user. The goal is that the movie doesn't have to be already in database, and the @PostMapping has to accept an user_id and movie name as parameters, other method uses the movie name, goes through the OMDBapi, parses data from json to fields and then gives the user at user_id the movie as a favourite. The PostMapping sort of works, because it gets the user at user_id, the movie is also added, but when the url looks like this - http://localhost:8080/users/2/fight+club the user at user_id 2 gets the movie as his favourite, but the movie gets it's id also as 2, even if it's first movie being added to repository. What I don't understand is why when I try to debug this every line of code is acting as I expect it to do - wUser(id=2, name=Jan, favouriteMovies=[Movie(id=1, title=Fight Club, plot=An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more., genre=Drama, director=David Fincher, posterURL=https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc@._V1_SX300.jpg)]) but after it passes repository.save(user) line I get redirected to InvocableHandlerMethod class, into doInvoke method, into

return KotlinDetector.isSuspendingFunction(method) ? this.invokeSuspendingFunction(method, this.getBean(), args) : method.invoke(this.getBean(), args);

this line, and after that it's just deep into the rabbit hole. As I am quite an inexperienced in coding in Java, what probably can be deducted, I don't really understand nor can find solution to this problem.
The entities and controller classes below

package com.example.omdbapirest.movie;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="movie_id")
    private Integer id;
    private String title;
    private String plot;
    private String genre;
    private String director;
    private String posterURL;

    public Movie(String title, String plot, String genre, String director, String posterURL) {
        this.title = title;
        this.plot = plot;
        this.genre = genre;
        this.director = director;
        this.posterURL = posterURL;
    }
}
package com.example.omdbapirest.user;

import com.example.omdbapirest.movie.Movie;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor

public class wUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
//    @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH})
    @OneToMany(cascade =CascadeType.ALL)
    @JoinColumn(name = "movie_id")
    private List<Movie> favouriteMovies;

    public wUser(String name) {
        this.name = name;
    }
}

UserController

package com.example.omdbapirest.user;

import com.example.omdbapirest.movie.Movie;
import com.example.omdbapirest.movie.MovieService;
import lombok.RequiredArgsConstructor;
import org.json.simple.parser.ParseException;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
     private final MovieService  movieService;
    private final UserRepository repository;
    private final UserService service;

    @GetMapping
    public List<wUser> getUsers(){
        return repository.findAll();
    }

    @PostMapping("/{id}/{moviename}")
    public void addMovieAsFavorite (@PathVariable (name= "id") int id,
                                    @PathVariable (name="moviename") String moviename)
            throws ParseException{
        String url = "https://www.omdbapi.com/?t="+moviename+"&apikey=30ccf40c";
        wUser user = repository.getById(id);
        List<Movie> movies = user.getFavouriteMovies();

        List<Movie>moviesToAdd = new ArrayList<>();
        Movie movie = movieService.getDataFromOMDBAsMovie(url);
        movies.add(movie);
        moviesToAdd.addAll(movies);
        user.setFavouriteMovies(moviesToAdd);
        repository.save(user);
    }
}

I'm also adding MovieService class in case there is some error in the JSON parser

package com.example.omdbapirest.movie;

import lombok.RequiredArgsConstructor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;

@Service
@RequiredArgsConstructor
public class MovieService {
    private final MovieRepository repository;
    public String getJSONFromURL(String strUrl) {
        String jsonText = "";

        try {
            URL url = new URL(strUrl);
            InputStream is = url.openStream();

            BufferedReader bufferedReader =
                    new BufferedReader(new InputStreamReader(is));

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                jsonText += line + "\n";
            }

            is.close();
            bufferedReader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return jsonText;
    }

    public Movie getDataFromOMDBAsMovie(String strURL) throws ParseException {
        String json = getJSONFromURL(strURL);

            Movie movie = new Movie();
            JSONParser parser = new JSONParser();
            Object object = parser.parse(json);
            JSONObject mainJsonObject = (JSONObject) object;
            String title = (String)mainJsonObject.get("Title");
            movie.setTitle(title);
            String plot = (String)mainJsonObject.get("Plot");
            movie.setPlot(plot);
            String genre = (String)mainJsonObject.get("Genre");
            movie.setGenre(genre);
            String director = (String)mainJsonObject.get("Director");
            movie.setDirector(director);
            String posterURL = (String)mainJsonObject.get("Poster");
            movie.setPosterURL(posterURL);
            repository.save(movie);
        return movie;
    }
    public Movie addMovie(Movie movie){
        return repository.save(movie);
    }
}

I tried adding movies to db, reworking the favourite saving class, all to no avail, I was getting different errors when not debuging, including

org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Pole nie może być NULL"MOVIE_ID"(Field cannot be NULL)
NULL not allowed for column "MOVIE_ID"; SQL statement:
update movie set movie_id=null where movie_id=? [23502-214]

and

org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Naruszenie ograniczenia Klucza Głównego lub Indeksu Unikalnego: "PRIMARY KEY ON PUBLIC.MOVIE(MOVIE_ID)(translating to- Unique Index or primary key violated)
 ( /* key:2 */ 2, 'David Fincher', 'Drama', 'An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more.', 'https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc@._V1_SX300.jpg', 'Fight Club')"
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.MOVIE(MOVIE_ID) ( /* key:2 */ 2, 'David Fincher', 'Drama', 'An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more.', 'https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc@._V1_SX300.jpg', 'Fight Club')"; SQL statement:
insert into movie (director, genre, plot, posterurl, title, movie_id) values (?, ?, ?, ?, ?, ?) [23505-214]

Both of these errors appear when I try to add another movie to given user, I mean I was able to give all users 1 movie, but never more since it tries to always add the movie with id of the user

y53ybaqx

y53ybaqx1#

让我们关注Map的相关部分:

public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="movie_id")
    private Integer id;
}

public class wUser {

    @OneToMany(cascade =CascadeType.ALL)
    @JoinColumn(name = "movie_id")
    private List<Movie> favouriteMovies;
}

Movieid属性会由Movie类别中的组态Map至数据表数据行movie_id
但是对于wUser.favouriteMovies,您使用@JoinColumn使其使用movie_id连接列,即Movie表中引用wUser的列。
通过这种方式,该列被Map到两个完全不同的值,在您的场景中,似乎是第二个值获胜。
要解决此问题,只需为联接列选择一个不同的列。user_id可能是一个不错的选择。

相关问题