jpa多对一关联在更新

时间:2016-03-29 09:33:49

标签: 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")
@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;
}}

我有这个会议附件表,用于存储附件的位置

package ng.telecomroadmap.model;

import java.io.Serializable;

import javax.persistence.*;




/**
 * The persistent class for the meetingsattachment database table.
 * 
 */
@Entity
@NamedQuery(name="Meetingsattachment.findAll", query="SELECT m FROM Meetingsattachment m")
public class Meetingsattachment implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int maid;

    private String attachment;

    //bi-directional many-to-one association to Meeting
    @ManyToOne
    @JoinColumn(name="meetingsid")
    private Meeting meeting;

    public Meetingsattachment() {
    }

    public int getMaid() {
        return this.maid;
    }

    public void setMaid(int maid) {
        this.maid = maid;
    }

    public String getAttachment() {
        return this.attachment;
    }

    public void setAttachment(String attachment) {
        this.attachment = attachment;
    }

    public Meeting getMeeting() {
        return this.meeting;
    }

    public void setMeeting(Meeting meeting) {
        this.meeting = meeting;
    }
    @Override
    public int hashCode() {

        final int prime = 31;
        int result = 1;
        result = prime * result + attachment.hashCode();
        return result;
    } 

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof Meetingsattachment))
            return false;
        Meetingsattachment other = (Meetingsattachment) obj;
        if (!(other.getAttachment()).equals(attachment))
            return false; 
        return true;
    }  
} 

我正在调用此方法来更新

public String updateButton(){
        List<Meetingsattachment> mal= meeting.getMeetingsattachments();

        //fileuploading code removed from here for troubleshooting


        mrm.updateMeeting(meeting); 



        return "meetings?faces-redirect=true";


    }

在我的实体经理

public void updateMeeting(Meeting meet){
        Meeting m=em.find(Meeting.class, meet.getMeetingsid());
        m.setDate(meet.getDate());
        m.setDescription(meet.getDescription());
        m.setMeetingsattachments(meet.getMeetingsattachments());

        em.flush();


    }

现在我的问题是,当我更新会议条目时,它会复制会议附件中已插入的值

示例:假设我与id 27会面并且在会议附件中我有以下

31  /path/to/files/t22-1700585698/1.pdf 27

现在,当我尝试编辑会议27并调用updatebutton方法而不更改任何内容或在会议附件表中附加任何新附件时,会发生以下情况

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();


}

3 个答案:

答案 0 :(得分:1)

我认为原因是您有两个Meeting类的不同实例:meetm

Meeting m=em.find(Meeting.class, meet.getMeetingsid());

m加载到持久性上下文中。由于关系为one-to-many,因此附件将会延迟加载。因此,它们不在持久化背景下。现在,当您在

中分配附件列表时
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();
}

原因是meet不是托管实例。持久性提供程序将在持久性上下文中创建一个新实例,并将meet的状态复制到它,然后在刷新em或提交事务时将保存到数据库中。因此,如果您不使用merge()方法中返回的实例,则更改(在本例中为日期)将不会保存到数据库中。

答案 1 :(得分:0)

不幸的是,这是一个疯狂的猜测,但你确定你的Meetingsattachment课程中的equals方法吗?看起来总会返回false =&gt; 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;
}}

答案 2 :(得分:0)

  1. Hibernate通过ID标识对象。
  2. Hibernate将仅在瞬态实体实例的数据库中插入新记录。
  3. 这意味着Meetingsattachment中包含的meet没有正确的ID(全部为零,对于基本类型似乎是默认的unsaved-value),因此Hibernate认为瞬态(新)。

    因此,解决方案是提供正确的ID并处理分离的对象,或者像在解决方法中一样手动合并集合。