我有一个数据库,我试图围绕它构建一个应用程序。问题是,当我试图将数据插入相关表时,我会间歇性地获得重复条目。
例如,有一个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);
}
1条答案
按热度按时间7ivaypg91#
如果
id
的值为零,并且只填充name
和其他属性,Hibernate将无法理解它是否是一个现有实体。如果id
的值为零,它将尝试持久化该数据。因此,当您提供输入actors数据的选项时,您应该有类似于现有actors的下拉列表,以及新actors的数据输入,因此,您的请求将为现有实体提供id
,为新实体提供零。现在,如果您使用saveOrUpdate
而不是save
,您的问题应该得到解决。saveOrUpdate
将确保不会再次保存现有的实体。仍然要确保,只需查看文档。如果您不确定实现,您当前的附加方法也很好,除非它会导致性能开销。使用
show_sql
实际查看后台发生的情况