找到了对集合多对多关系的共享引用



我有这个方法:

@Override 
public Movie createMovie(Movie movie) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JwtUser user = (JwtUser)authentication.getPrincipal();
User current_user = userRepository.findOne(user.getId());       
movieRepository.save(movie);
userRepository.save(new HashSet<User>(){{
add(new User(current_user, new HashSet<Movie>(){{
add(movie);
}}));
}});
return movieRepository.save(movie);
}

当我运行我的应用程序并调用该函数时,我会收到以下错误:

找到对集合的共享引用:com.moviesat.model.security.User.movies

在我的用户模型中,我有:

@ManyToMany
@JoinTable(name = "user_movie",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "movie_id", referencedColumnName = "id")
)
private Set<Movie> movies;

在我的电影模型中,我有:

@ManyToMany(mappedBy = "movies", cascade = CascadeType.ALL)
private Set<User> users = new HashSet<>(); 
public Set<User> getUsers() {
return users;
}

是什么导致了错误?

根据我对代码的理解,您正试图在数据库中创建一个Movie,并将其绑定到当前的User。如果我错了,请纠正我。

首先,正如您可能从Hibernate用户指南中了解到的那样,双向@ManyToMany关联应该以不同的方式定义和使用。

双向@ManyToMany关联具有owning和mappedBy端。为了保持双方之间的同步性,最好提供用于添加或删除子实体的辅助方法。

其次,不应在@ManyToMany关联上使用CascadeType.ALL

对于@ManyToMany关联,REMOVE实体状态转换级联没有意义,因为它将传播到链接表。由于另一侧可能被其他实体引用在父级,自动删除可能会以ConstraintViolationException。

例如,如果定义了@ManyToMany(cascade=CascadeType.ALL),并且第一个人将被删除,Hibernate将抛出异常因为另一个人仍然与正在删除。

因此,我们应该将cascade移动到拥有方,更改级联类型,为User提供辅助方法,并在我们的业务逻辑中仅更新关联的拥有方(User)。让我们更改代码。

用户型号:

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "user_movie",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "movie_id", referencedColumnName = "id")
)
private Set<Movie> movies = new HashSet<>();
public void addMovie(Movie movie) {
movies.add(movie);
movie.getUsers().add(this);
}
public void removeMovie(Movie movie) {
movies.remove(movie);
movie.getUsers().remove(this);
}

电影型号:

@ManyToMany(mappedBy = "movies")
private Set<User> users = new HashSet<>();

以及业务逻辑:

@Override
public Movie createMovie(Movie movie) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JwtUser user = (JwtUser)authentication.getPrincipal();
User current_user = userRepository.findOne(user.getId());
current_user.addMovie(movie);
userRepository.save(current_user);
return movie;
}

最新更新