休眠多对多和java.sql.SQLIntegrityConstraintViolationException:重复输入错误

chhkpiq4  于 2023-03-21  发布在  Java
关注(0)|答案(1)|浏览(206)

我有一个数据库,我试图围绕它构建一个应用程序。问题是,当我试图将数据插入相关表时,我会间歇性地获得重复条目。
例如,有一个Video实体和一个Actor实体,每个视频中有很多演员,每个演员都演过几部电影,所以连接是多对多。

@Entity
@Table(name = "videos")
public class Video implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private int year;

    @ManyToMany(cascade = {CascadeType.ALL})
    @JoinTable(
            name = "film_actors",
            joinColumns = @JoinColumn(name = "film_id"),
            inverseJoinColumns = @JoinColumn(name = "actor_id")
    )
    private Set<Actor> actors = new HashSet<>();

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Video video = (Video) o;

        return title != null ? title.equals(video.title) : video.title == null;
    }

    @Override
    public int hashCode() {
        return title != null ? title.hashCode() : 0;
    }

    //getters setters
}

@Entity
@Table(name = "actors")
public class Actor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(unique = true)
    private String name;

    @ManyToMany(mappedBy = "actors")
    private Set<Video> video = new HashSet<>();

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Actor actor = (Actor) o;

        return name != null ? name.equals(actor.name) : actor.name == null;
    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }
}

问题是,当我尝试在服务中保存一个新的Video实体时,如果actors表中已经有一个actors(同名),我会收到一个错误,即无法插入该实体,这是合理的,因为表对www.example.com列有唯一性约束Actor.name。
我希望hibernate能够理解Actors表中已经有了一个唯一的值,并且不会试图再次插入同名的actor,获取其id并将其放入关联的film_actor表中。
这可以做到吗?
现在我正在做这样的事情来解决我的问题,这似乎不是正确的解决方案。这是唯一的方法吗?

@Override
    public void save(Video video) throws SQLException {

        Set<Actor> actors = video.getActors();
        Set<Actor> mapped = new HashSet<>();
        for (Actor actor : actors) {
            Actor fromDb = actorRepository.findByName(actor.getName());
            if (fromDb != null) {
                mapped.add(fromDb);
            } else {
                mapped.add(actor);
            }
        }
        video.setActors(mapped);

        videoRepository.save(video);
    }
7ivaypg9

7ivaypg91#

如果id的值为零,并且只填充name和其他属性,Hibernate将无法理解它是否是一个现有实体。如果id的值为零,它将尝试持久化该数据。因此,当您提供输入actors数据的选项时,您应该有类似于现有actors的下拉列表,以及新actors的数据输入,因此,您的请求将为现有实体提供id,为新实体提供零。现在,如果您使用saveOrUpdate而不是save,您的问题应该得到解决。
saveOrUpdate将确保不会再次保存现有的实体。仍然要确保,只需查看文档。如果您不确定实现,您当前的附加方法也很好,除非它会导致性能开销。
使用show_sql实际查看后台发生的情况

相关问题