jpa多对一关联在更新时创建重复
我有下面的会议桌jpa多对一关联在更新时创建重复,jpa,duplicates,many-to-one,Jpa,Duplicates,Many To One,我有下面的会议桌 package ng.telecomroadmap.model; import java.io.Serializable; import javax.persistence.*; import java.util.Date; import java.util.List; /** * The persistent class for the meetings database table. * */ @Entity @Table(name="meetings")
package ng.telecomroadmap.model;
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
/**
* The persistent class for the meetings database table.
*
*/
@Entity
@Table(name="meetings")
@NamedQuery(name="Meeting.findAll", query="SELECT m FROM Meeting m")
public class Meeting implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int meetingsid;
@Temporal(TemporalType.DATE)
private Date date;
private String description;
//bi-directional many-to-one association to Meetingsattachment
@OneToMany(mappedBy="meeting", cascade = CascadeType.PERSIST)
private List<Meetingsattachment> meetingsattachments;
public Meeting() {
}
public int getMeetingsid() {
return this.meetingsid;
}
public void setMeetingsid(int meetingsid) {
this.meetingsid = meetingsid;
}
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Meetingsattachment> getMeetingsattachments() {
return this.meetingsattachments;
}
public void setMeetingsattachments(List<Meetingsattachment> meetingsattachments) {
this.meetingsattachments = meetingsattachments;
}
public Meetingsattachment addMeetingsattachment(Meetingsattachment meetingsattachment) {
getMeetingsattachments().add(meetingsattachment);
meetingsattachment.setMeeting(this);
return meetingsattachment;
}
public Meetingsattachment removeMeetingsattachment(Meetingsattachment meetingsattachment) {
getMeetingsattachments().remove(meetingsattachment);
meetingsattachment.setMeeting(null);
return meetingsattachment;
}}
我正在调用此方法以进行更新
public String updateButton(){
List<Meetingsattachment> mal= meeting.getMeetingsattachments();
//fileuploading code removed from here for troubleshooting
mrm.updateMeeting(meeting);
return "meetings?faces-redirect=true";
}
现在我的问题是,当我更新会议记录时,它会复制会议附件中已插入的值
示例:假设我有一个id为27的会议,在会议附件中我有以下内容
31 /path/to/files/t22-1700585698/1.pdf 27
现在,当我尝试编辑meeting 27并调用updatebutton方法而不更改任何内容或在meetings附件表中附加任何新附件时,会发生以下情况
31 /path/to/files/t22-1700585698/1.pdf 27
32 /path/to/files/t22-1700585698/1.pdf 27
我不知道我做错了什么,会议附件又被添加到数据库中了
从下面的答案中,我了解到问题在于会议附件不在持续的上下文中,但我仍然不确定如何解决这个问题
目前的解决方案对我有效,但我不认为它是理想的
public void updateMeeting(Meeting meet){
Meeting m=em.find(Meeting.class, meet.getMeetingsid());
m.setDate(meet.getDate());
m.setDescription(meet.getDescription());
List<Meetingsattachment> mal = m.getMeetingsattachments();
for(Meetingsattachment ma:meet.getMeetingsattachments()){
if(!mal.contains(ma)){
m.addMeetingsattachment(ma);
}
}
//m.setMeetingsattachments(meet.getMeetingsattachments());
em.flush();
}
公共作废更新会议(会议){
Meeting m=em.find(Meeting.class,meet.getMeetingsid());
m、 setDate(meet.getDate());
m、 setDescription(meet.getDescription());
List mal=m.getMeetingsattachments();
for(Meetingsattachment ma:meet.getMeetingsattachments()){
如果(!mal.contains(ma)){
m、 添加会议附件(ma);
}
}
//m、 setMeetingsattachments(meet.getMeetingsattachments());
em.flush();
}
不幸的是,这是一个胡乱猜测,但您确定Meetingsattachment类中的equals方法吗?看起来它总是返回false=>jpa找不到附件,所以它会创建一个新附件
编辑:一些代码
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Meetingattachment))
return false;
String other = (Meetingattachment) obj.getAttachment;
if (!other.equals(attachment))
return false;
return true;
}}
我认为原因是你有两个不同的
Meeting
类实例:Meeting
和m
Meeting m=em.find(Meeting.class, meet.getMeetingsid());
将m
加载到持久性上下文中。因为关系是一对多,附件将被延迟加载。因此,它们不在持久性上下文中。现在,当您在中分配附件列表时
m.setMeetingsattachments(meet.getMeetingsattachments());
它们将被视为新条目,并将被持久化。
这应该是你得到重复的原因
因此,如果updateMeeting()
方法按如下方式实现,则问题应该得到解决:
public void updateMeeting(Meeting meet){
em.merge(meet);
em.flush();
}
需要另一个引用(如m
)的唯一情况是,如果要在updateMeeting()
方法中更改托管实体的状态,例如:
public void updateMeeting(Meeting meet){
Meeting m = em.merge(meet);
m.setDate(<some_date>);
em.flush();
}
公共作废更新会议(会议){
会议m=em.merge(会议);
m、 设置日期();
em.flush();
}
原因是meet
将不是托管实例。持久性提供程序将在持久性上下文中创建一个新实例,并将meet
的状态复制到该实例中,然后在刷新em
或提交事务时将其保存到数据库中。因此,如果不使用从merge()
方法返回的实例,更改(在本例中是日期)将不会保存到数据库中
Meetingsattachment
中包含的meeting
没有正确的ID(都是零,这似乎是基本类型的默认值),因此Hibernate认为它们是暂时的(新的)
因此,解决方案是提供适当的ID并处理分离的对象,或者手动合并集合,就像您已经在解决方案中所做的那样 你是对的,equals方法是错误的,但不幸的是,修复它并没有解决问题,同样的事情还在发生。我编写了equals方法,用于我为排除故障而删除的文件上载代码,以确保我只在meetingsattachment列表中插入唯一值。如果您注释掉
m.setMeetingsattachments(meet.getMeetingsattachments())代码>发生了什么?我很确定你是对的,但我不知道如何解决这个问题,我能想到的唯一解决方案是一个非常肮脏的解决方案,我在meet和m中循环使用附件,然后删除重复的附件,然后执行m.setMeetingsattachments(meet.getMeetingsattachments());就我在上面的代码中所见,在updateMeeting()
方法中没有您正在做的事情。因此,您只需要方法中的以下行,其余部分应按预期工作:public void updateMeeting(Meeting-Meeting){em.merge(Meeting);}
。原因是,您的实体具有数据库标识,使得持久性提供者将其视为一个分离的实体并将其合并。它工作了,谢谢,我到处读过,除非使用大容量操作,否则不应该使用合并。请在答案中加入合并内容,我会将其标记为已接受。谢谢again@yahh:修改了答案。
public void updateMeeting(Meeting meet){
em.merge(meet);
em.flush();
}
public void updateMeeting(Meeting meet){
Meeting m = em.merge(meet);
m.setDate(<some_date>);
em.flush();
}