鍍金池/ 問答/Java  網(wǎng)絡(luò)安全/ 請(qǐng)教一個(gè)JPA多對(duì)多級(jí)聯(lián)保存的問題

請(qǐng)教一個(gè)JPA多對(duì)多級(jí)聯(lián)保存的問題

實(shí)體類

// 標(biāo)簽類
@Entity
public class Label {
    @Id
    @Column(name = "lid",unique = true,nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer lid;
    private String tag;
    @ManyToMany(fetch = FetchType.EAGER)
    @Cascade(value = {CascadeType.ALL}) // 設(shè)置級(jí)聯(lián)關(guān)系
    @JoinTable(name = "song_label",// 指定第三張表
            joinColumns = {@JoinColumn(name = "label_id")},//本表與中間表的外鍵對(duì)應(yīng)
            inverseJoinColumns = {@JoinColumn(name = "song_id")}
        )
    private Set<Song> songs = new HashSet<>();
    // setter and getter
 }

// 歌曲類
@Entity
public class Song {
    @Id
    @Column(name = "sid",unique = true,nullable = false)
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer sid;
    private String title;
    private String special;
    @ManyToMany(fetch = FetchType.EAGER)
    @Cascade(value = { CascadeType.ALL})
    @JoinTable(
            name = "song_label",
            joinColumns = {@JoinColumn(name = "song_id")},//本表與中間表的外鍵對(duì)應(yīng)
            inverseJoinColumns = {@JoinColumn(name = "label_id")}
    )
    private Set<Label> labels = new HashSet<>();
     // setter and getter
  }

關(guān)聯(lián)關(guān)系: 一首歌曲可以對(duì)應(yīng)多個(gè)標(biāo)簽,一個(gè)標(biāo)簽可以對(duì)應(yīng)多首歌曲

遇到的級(jí)聯(lián)保存問題: 在添加已經(jīng)存在的標(biāo)簽記錄時(shí)保錯(cuò)org.hibernate.PersistentObjectException: detached entity passed to persist
測試代碼

    @Test
    public void test1() {
        Song song = new Song();
        song.setSpecial("等你下課");
        song.setTitle("等你下課");

        Label label1 = new Label();
        label1.setTag("華語");
        Label label2 = new Label();
        label2.setTag("內(nèi)地");
        song.getLabels().add(label1);
        song.getLabels().add(label2);

        this.songDao.save(song);//因設(shè)置級(jí)聯(lián)關(guān)系CascadeType.ALL相應(yīng)會(huì)在Label表添加記錄
    }
    
        @Test
        public void test123(){
            Song song = new Song();
            song.setSpecial("流星花園");
            song.setTitle("北極星的眼淚");
            Label label1 = this.labelDao.findByTag("愛情");
            Label label2 = this.labelDao.findByTag("華語");
            if (label2 == null){
                label2 = new Label();
                label2.setTag("華語");
            }
            if(label1 == null){
                label1 = new Label();
                label1.setTag("愛情");
            }
    
            song.getLabels().add(label1);
            song.getLabels().add(label2);
    
            this.songDao.save(song);// 報(bào)錯(cuò)org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.data.bean.Label
        }

test1()能夠添加成功,到了test2時(shí)由于Label表存在"華語"這條記錄,保存會(huì)出錯(cuò)
疑問:如何在Label表存在記錄時(shí)執(zhí)行更新而不是保存?

在此先感謝大神路過指點(diǎn)迷津哈哈

回答
編輯回答
半心人

只需要將CascadeType.ALL修改為CascadeType.MERGE
然后在新增數(shù)據(jù)時(shí)自己手動(dòng)關(guān)聯(lián)表即可

 @Test
 public void test123(){
     
        this.labelDao.save(label1);
        this.labelDao.save(label2);
        this.songDao.save(song);// 報(bào)錯(cuò)org.hibernate.PersistentObjectException: detached entity passed to persist: com.example.data.bean.Label
        }
2017年5月1日 21:27