欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
[譯文]JPA的實(shí)施模式:刪除實(shí)體

原文:JPA implementation patterns: Removing entities

作者:Vincent Partington

出處:http://blog.xebia.com/2009/04/09/jpa-implementation-patterns-removing-entities/

 

過(guò)去幾周以來(lái)我一直在談?wù)撟约涸诰帉?xiě)JPA應用時(shí)發(fā)現的實(shí)施模式,上兩篇博客分別涉及了保存實(shí)體和檢索實(shí)體方面的內容,不過(guò)在真正完全實(shí)現實(shí)體的時(shí)候,我猜你是希望也能夠對它們進(jìn)行刪除操作的,所以,刪除就是本篇博客的主題。

就像檢索實(shí)體一樣,刪除一個(gè)實(shí)體是很簡(jiǎn)單的,實(shí)際上,所有需要做的就是把實(shí)體傳給EntityManager.remove方法(當然實(shí)際上是調用了DAO的一個(gè)刪除方法,該方法轉而調用EntityManager.remove),以便在事務(wù)提交的時(shí)候從數據庫中刪除該實(shí)體。通常情況下,這一切就是這么回事,不過(guò),事情會(huì )因為你正在使用關(guān)聯(lián)(無(wú)論它們是雙向的與否)而變得更有意思起來(lái)。

 

刪除作為關(guān)聯(lián)的組成部分的實(shí)體

 

考慮一下之前我們討論過(guò)的OrderOrderLine類(lèi)這一例子,比方說(shuō),我們要從Order中刪除OrderLine,我們以這種簡(jiǎn)單的方式來(lái)完成這件事:

 

orderLineDao.remove(lineToDelete);

 

這一代碼是有問(wèn)題的,當你告訴實(shí)體管理器刪除該實(shí)體的時(shí)候,實(shí)體管理器并不會(huì )自動(dòng)地從指向該實(shí)體的所有關(guān)聯(lián)中刪除它,就像JPA不會(huì )自動(dòng)地管理雙向關(guān)聯(lián)一樣,就例子中的情況而言,關(guān)聯(lián)指的應該是OrderLine.order屬性指向的Order對象中的orderLines集合。假如我要把這一描述寫(xiě)成一個(gè)測試失敗的JUnit用例的話(huà),那它應該是這樣的:

 

OrderLine orderLineToRemove = orderLineDao.findById(someOrderLineId);

Order parentOrder = orderLineToRemove.getOrder();

int sizeBeforeRemoval = parentOrder.getOrderLines().size();

orderLineDao.remove(orderLineToRemove);

assertEquals(sizeBeforeRemoval - 1, parentOrder.getOrderLines().size());

 

影響

 

這一測試用例的失敗有兩處不易察覺(jué)也因此是比較惡劣的影響:

           在刪除OrderLine之后,任何使用Order對象的代碼相反仍然會(huì )看到被刪除的OrderLine,只有在提交該事務(wù),然后開(kāi)始一個(gè)新的事務(wù)并在新事務(wù)中重新加載Order之后,被刪除的OrderLine才不會(huì )在Order.orderLines集中出現。在簡(jiǎn)單的情況下我們不會(huì )遇到這一問(wèn)題,但在事情越來(lái)越復雜的時(shí)候,我們可能會(huì )被這些“僵尸”OrderLines的出現嚇一跳。

           當持久操作從Order對象級聯(lián)到Order.orderLines關(guān)聯(lián)并且其包含的Order對象沒(méi)有在同一事務(wù)中被刪除時(shí),我們將會(huì )收到諸如“已刪除的實(shí)體被傳給了持久方法”一類(lèi)的錯誤。不同于我們在之前的博客中談到的“游離實(shí)體被傳給了持久方法”這一錯誤,當前的這一錯誤是由Order對象擁有到已被刪除的OrderLine對象的引用這一事實(shí)導致的,JPA提供程序在把持久性上下文中的實(shí)體刷新到數據庫中時(shí)發(fā)現了該引用,造成其企圖持久已經(jīng)被刪除的實(shí)體,從而導致了錯誤的出現。

 

簡(jiǎn)單的解決方案

 

為了解決這一問(wèn)題,我們還必須從Order.orderlines集中刪除OrderLine,這聽(tīng)起來(lái)非常熟悉……實(shí)際上,在管理雙向關(guān)聯(lián)時(shí),我們也需要確保關(guān)聯(lián)的兩端保持一致的狀態(tài),這意味著(zhù)我們可以重用在這方面用過(guò)的模式,通過(guò)把對orderLineToRemove.setOrder(null)的調用加入到測試中來(lái)使其成功運行:

 

OrderLine orderLineToRemove = orderLineDao.findById(someOrderLineId);

Order parentOrder = orderLineToRemove.getOrder();

int sizeBeforeRemoval = parentOrder.getOrderLines().size();

orderLineToRemove.setOrder(null);

orderLineDao.remove(orderLineToRemove);

assertEquals(sizeBeforeRemoval - 1, parentOrder.getOrderLines().size());

 

模式

不過(guò)類(lèi)似這樣的做法會(huì )使代碼變得脆弱,因為其依賴(lài)于領(lǐng)域對象的用戶(hù)調用正確的方法,DAO應該承擔這一工作。一個(gè)非常棒的解決這一問(wèn)題的方法是像這樣子來(lái)使用@PreRemove這一實(shí)體生命周期的鉤子:

 

@Entity

public class OrderLine {

         [...]

 

         @PreRemove

         public void preRemove() {

                   setOrder(null);

         }

}

 

現在我們只要調用OrderLineDao.remove()來(lái)除去不想要的OrderLine對象就可以了。

本篇博客最初是建議引入由DAO來(lái)調用的帶有preRemove方法的HasPreRemove接口,不過(guò)Sakuraba建議說(shuō),@PreRemove注解正好是我們這里要用到的東西,再次感謝你,Sakuraba!

 

刪除孤兒

 

但是你會(huì )問(wèn),如果我們只是要從Order.orderLines集中刪除OrderLine的話(huà),那事情會(huì )怎么樣呢?

 

Order parentOrder = orderLineToRemove.getOrder();

parentOrder.removeOrderLine(orderLineToRemove);

 

OrderLine確實(shí)已是從Order.orderlines集中刪除,并且不僅僅只是在該事務(wù)中,如果我們在新的事務(wù)中再次檢索該Order對象的話(huà),被刪除的OrderLine也不會(huì )出現。但是如果我們查看一下數據庫,就會(huì )看到該OrderLine還在,它只是把OrderLine.order字段設置成null罷了,我們在這里看到的是一個(gè)“已成孤兒的”集合元素,解決這一問(wèn)題有兩種方法:

           如我們之前討論的那樣,顯式地刪除OrderLine對象。

           如果正在使用Hibernate作為JPA提供程序的話(huà),可以讓Hibernate自動(dòng)地刪除這些孤兒,對你希望Hinernate這樣做的@OneToMany注解來(lái)說(shuō),在其下面添加值為org.hibernate.annotations.CascadeType.DELETE_ORPHANorg.hibernate.annotations.Cascade注解,可參閱Hinernate文檔中的例子。

 

雖然第二種解決方案是供應商特定的,但確實(shí)有它的好處在,那就是代碼不需要每次從集合中刪除實(shí)體的時(shí)候都要調用DAO的刪除方法,不過(guò)為了明確地表明你是在使用供應商特定的擴展,你應該使用完整的包名稱(chēng)(既然Java Persistence with Hibernate一書(shū)也這樣建議)來(lái)引用這些注解:

 

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)

@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

private Set<OrderLine> orderLines = new HashSet<OrderLine>();

 

需要注意的是,CascadeType.All并未包含DELETE_ORPHAN這一級聯(lián)類(lèi)型,這就是為什在這里的例子中要顯式地設定它。

因此,我們可以得出結論,刪除實(shí)體是件簡(jiǎn)單的工作,除非你正在處理關(guān)聯(lián),在這種情況下需要特別小心,要確保從所有指向實(shí)體的對象中刪除該實(shí)體,并且同時(shí)要從數據庫中刪除它。我們下一篇博客中再見(jiàn)!在此期間,請在下面的評論部分中留下任何想說(shuō)的話(huà)。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
hibernate+jpa
Struts 2 + Spring 2 + JPA + AJAX
Hibernate 注解中CascadeType用法匯總
如何避免出現SQL注入漏洞
使用Eclipse通過(guò)連接數據庫生成實(shí)體類(lèi)和映射文件
Spring Boot:在Spring Boot中使用Mysql和JPA
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久