JPA實(shí)體關(guān)系映射補(bǔ)遺:有關(guān)mappedBy的思考

本文閱讀時(shí)間3分鐘。由作者三汪首發(fā)于簡(jiǎn)書。


幾個(gè)月前寫了一篇《JPA實(shí)體關(guān)系映射:@ManyToMany多對(duì)多關(guān)系、@OneToMany@ManyToOne一對(duì)多多對(duì)一關(guān)系和@OneToOne的深度實(shí)例解析》,簡(jiǎn)要闡述了我對(duì)JPA的幾個(gè)實(shí)體關(guān)系映射的理解。
其中有關(guān)mappedBy的部分是這樣寫的:

mappedBy聲明于關(guān)系的被維護(hù)方,聲明的值為關(guān)系的維護(hù)方的關(guān)系對(duì)象屬性名。
在實(shí)例中,mappedBy被聲明于Course類中,其值為Student類中的Set對(duì)象"courses"。即,Student為關(guān)系維護(hù)方,Course為被維護(hù)方。

這個(gè)表述其實(shí)是沒錯(cuò)的。但是我后面又補(bǔ)充了一句:

但是在實(shí)際操作中,我發(fā)現(xiàn)其實(shí)被維護(hù)方于維護(hù)方的概念并不那么重要。被維護(hù)方也可以對(duì)雙方關(guān)系進(jìn)行維護(hù)。下面通過一組測(cè)試用例來進(jìn)行說明。

然而今天測(cè)試小哥給我提了個(gè)bug,讓我發(fā)現(xiàn)到其實(shí)mappedBy其實(shí)并非不重要的。


和測(cè)試小哥的對(duì)話

事實(shí)上這是一個(gè)很簡(jiǎn)單的bug。
通過查看日志,發(fā)現(xiàn)hibernate打印出來的sql中,不僅有update語句,還出現(xiàn)了delete語句。
這是因?yàn)榍岸藗鬟^來的數(shù)據(jù)里是不帶關(guān)聯(lián)對(duì)象的。
所以只要從數(shù)據(jù)庫里把關(guān)聯(lián)找出來然后賦給編輯的對(duì)象就解決了。

像這樣:
修改前

    @Override
    @Transactional
    public void saveLabelDict(LabelDictDomain labelDictDomain) {
        if (labelDictDomain.getLabelType().equals(TYPE_UNIFORM)) {          
            if (StringUtil.isEmpty(labelDictDomain.getLabelGroup())) {
                throw new BizException("統(tǒng)一標(biāo)簽標(biāo)簽分組不能為空!");
            }           
        }else if(!labelDictDomain.getLabelType().equals(TYPE_PERSONAL)){
            throw new BizException("標(biāo)簽類型非法!");
        }
        repository.save(labelDictDomain);
    }

修改后

    @Override
    @Transactional
    public void saveLabelDict(LabelDictDomain labelDictDomain) {
        if (labelDictDomain.getLabelType().equals(TYPE_UNIFORM)) {          
            if (StringUtil.isEmpty(labelDictDomain.getLabelGroup())) {
                throw new BizException("統(tǒng)一標(biāo)簽標(biāo)簽分組不能為空!");
            }           
        }else if(!labelDictDomain.getLabelType().equals(TYPE_PERSONAL)){
            throw new BizException("標(biāo)簽類型非法!");
        }
        if (StringUtil.isNotEmpty(labelDictDomain.getId())) {
            LabelDictDomain domain = repository.findOne(labelDictDomain.getId());
            labelDictDomain.getMemberDomains().addAll(domain.getMemberDomains());
        }
        repository.save(labelDictDomain);
    }

這個(gè)修改引發(fā)了我對(duì)于關(guān)系映射的思考。
因?yàn)樵谂c之相關(guān)的另外一個(gè)實(shí)體編輯時(shí),并不需要這樣子手動(dòng)去配置關(guān)聯(lián)關(guān)系。
相關(guān)代碼如下

      @Override
    @Transactional
    public MemberDomain addMember(MemberDomain memberDomain) {
        
        //無關(guān)代碼略

        memberDomain.getBonusPointDomains().clear();
        memberDomain.getFavoriteInfoDomains().clear();
        memberDomain.getLabelDictDomains().clear();
        memberDomain.setPointTotal(null);

        memberDomain = repository.save(memberDomain);   
        return memberDomain;

    }

在這里我不僅沒有手動(dòng)配置關(guān)聯(lián)關(guān)系,還為了維護(hù)數(shù)據(jù)安全,把其他實(shí)體關(guān)聯(lián)給清空了。
但是這里卻不會(huì)產(chǎn)生delete語句影響數(shù)據(jù)庫里的內(nèi)容。
這是為什么呢。

在看了一眼實(shí)體中的關(guān)聯(lián)配置以后,我突然恍然大悟。
其實(shí)都是因?yàn)檫@個(gè)小小的沒有被注意到的mappedBy啊。
因?yàn)?code>LabelDictDomain中的memberDomains對(duì)象在MemberDomain中被配置為了關(guān)系的維護(hù)方。
所以labelDictDomains可以為空,而memberDomains一定不能為空。
否則就會(huì)出現(xiàn)關(guān)聯(lián)關(guān)系被清空的情況。
也就是說,被維護(hù)方不會(huì)主動(dòng)去維護(hù)關(guān)聯(lián)關(guān)系。
真正的關(guān)系維護(hù),掌握在維護(hù)方的手中。

關(guān)聯(lián)配置代碼如下
被維護(hù)方:

        @ManyToMany(mappedBy = "memberDomains", cascade={CascadeType.MERGE,CascadeType.DETACH} , fetch =  FetchType.EAGER)
        private Set<LabelDictDomain> labelDictDomains = new HashSet<>();

維護(hù)方:


         @ManyToMany(cascade={CascadeType.DETACH} , fetch =  FetchType.LAZY)
         @JoinTable(name="member_label",joinColumns = { @JoinColumn(name="LABEL_ID")},inverseJoinColumns = @JoinColumn(name="MEMBER_ID"))
         private Set<MemberDomain> memberDomains = new HashSet<>();

以上。
希望我的文章對(duì)你能有所幫助。
我不能保證文中所有說法的百分百正確,但我能保證它們都是我的理解和感悟以及拒絕復(fù)制黏貼。
有什么意見、見解或疑惑,歡迎留言討論。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容