一、本節簡介
上一節我們講的是擴展屬性,說白了就是從Subject中點出Teacher,從Teacher中可以點出Subject的List. 通常在實際應用中,我們刪除了Teacher,那么這個老師所帶的課程也就沒有用了,因為Subjcet沒有任課老師了.所以我們希望,在刪除Teacher的時候同時一起刪除的還有那些課程.所以就有了級聯操作.
二、邏輯關系
在演示級聯操作之前,我們先理一下關系,一個課程對應了一個老師,而一個老師可以帶多個課目, 這樣一來刪除老師的時候可以把其下的所有課目給刪掉,但是刪科目的時候,不可以刪除老師,因為其他科目還關聯着這個老師.邏輯關系理清了,然后我們來介紹XCode中的級聯操作.
三、關於Delete和OnDelete以及其他的一些說明
XCode中我們可以通過重載OnDelete,Delete,OnUpdate,Update這些方法.
我們來看看Delete方法吧.在Delete方法進行驗證過后調用了OnDelete方法,也就是說OnDelete方法才是正真的數據庫刪除操作.
同時,我們看到了Delete的說明,如果實體沒有完整信息,那么就無法通過擴展屬性刪除附屬數據.
這個是什么意思呢? 解釋一下,通常我們可能碰到這樣的情況,在一個列表中,點擊某一列后面的刪除按鈕,這個時候我們都是通過Post參數的方式來獲取到需要刪除的那行數據的主鍵ID,在程序里我們可能會這么寫
string strid = Request.QueryString["id"]; int id = -1; if (!int.TryParse(strid, out id)) throw new Exception("非法參數!"); //第一種方法直接用實體靜態方法刪除 Domain.Teacher.Delete(new string[] {Domain.Teacher._.ID}, new object[] {id}); //第二種方法new一個實體刪除
Domain.Teacher teacher = new Domain.Teacher() {ID = id};
teacher.Delete();
//第二種方法先查詢,后刪除 Domain.Teacher.FindByID(id).Delete();
那么三種方法有什么區別?
首先第一種,是不推薦這么寫的,這樣寫呢就相當於你組了一條SQL, Delete From teacher where id = 1; XCode由於沒有獲取到實體什么都幫不了你,更重要的是,XCode不會幫你刪除和更新Cache中的內容,也就是說直到下一次Cache過期前,你刪除的那條數據,還是存在中Cache,如果別人在查詢的時候就會命中Cache,造成數據的不統一;
第二種方法,這種方法僅適用於ID為自增主鍵的情況,XCode會自動幫你嘗試級聯刪除,但是不能保證所有的級聯都能刪除掉,原因我們在后面的舉例.這里提一下,因為實體除了ID其他所有的屬性都是null;
第三種方法是最推薦的方法,首先對於一個曾經有性能潔癖的人來說,我是不喜歡查詢后刪除的,但是這里大石頭告訴我,這種查詢不會超過20ms,這是主鍵查詢啊! 主鍵查詢是最快的了.沒有什么能比主鍵查詢還快的了,所以這個性能的損耗可以忽略不記,但是帶來的優勢卻是級聯操作的完整性和Cache的操作的完整性.
四、XCode中如何寫級聯操作
首先我們已經知道重載OnDelete,OnUpdate即可.所以操作起來很簡單.而且本節我們不用給XCode編寫任何代碼,XCode代碼生成器已經幫我們做好了,各位看官可以打開Teacher.Biz.cs第54行可以看到已經重載了OnDelete了
protected override int OnDelete() { if (Subjects != null) Subjects.Delete(); return base.OnDelete(); }
這里對代碼做一些解說,同時也是對上面第二種方法的進一步說明,為什么級聯操作會不完整.同時也是對上一節擴展屬性的進一步鞏固.if(Subjects != null)
這里的Subjects就是上一節我們說的擴展屬性,程序是死的,程序是沒有思想的,所以他會去找到這個Subject屬性,然后進入get方法,判斷發現_Subject確實是null 而且id>0並且字典里也是不存在相應數據,所以就會去執行FindAllByTeacherID的方法來填充這個Subjects,到這個Get結束,我們的teacher這個new出來的對象除了id和subjects兩個屬性不是null外 其他屬性仍然是null,不要以為XCode會智能的幫你把其他屬性給自動獲取,這個Subjets正好是你get方法寫的巧合,是靠ID來查找的.
舉個例子,如果Teacher類中有一個屬性是OfficeID,這個OfficeID又關聯到另一張表Office,也就是說多個教師在一個辦公室中,還可以查某個辦公室有哪些老師,這個時候,由於你是new的一個teacher實體,並且除了id外其他都是null
所以即使你寫了一個Office的擴展屬性,跑到Get方法里執行到_Office = Office.FindAllByOfficeID(OfficeID); 這個地方的OfficeID是null,要么報錯,要么就是查不到.總之你的級聯操作就是不完整的.
五、其他的級聯操作
雖然上面我們沒有要自己寫代碼,但是通常我們是要自己來完善代碼邏輯的,譬如Update的時候XCode就沒有幫我們生成代碼,我們只要記住一點,重載OnUpdate,並且在最后調用base.OnUpdate()方法即可.
舉個實際應用中的例子,可能和級聯操作沒有太大關系,但是卻是重載OnUpdate和OnDelete有關的,通常我們一個用戶會有個頭像,數據庫中保存的是頭像的相對地址,那么如果用戶修改或刪除了呢,關聯的頭像不就沒有用了嗎,如果不刪除物理文件的話,那日積月累下來磁盤上的垃圾頭像越來越多,我們不得不去手動清理或做其他的處理.
這個時候如果在Update或Delete的時候重載方法,加上你磁盤操作的方法就可以在編輯和刪除的時候就把那些沒有用的垃圾頭像給清理掉了.
具體怎么寫?還要我教你?好吧,我就簡單的寫一下吧,磁盤操作不是本節的重點,你可以在網上找到很多這樣的方法.
寫到這里突然想到,之前項目里碰到的問題,delete是好辦,可是update的時候,各位看官想一想,Teacher.Pic= "xxx" ; Teacher.Update(); 這個時候Pic已經變了!!!! 我不知道我要去操作磁盤上哪個文件了...怎么辦...怎么辦...當時樓主的性能潔癖又犯了,就是不願意查詢數據庫啊,死活不願意啊.想盡各種辦法,求助大石頭,求助群友,最后得到的結論是象這樣的update操作又不頻繁!主鍵查詢速度是最快的!性能潔癖! 所以樓主妥協了,其實這種主鍵查詢一次數據庫要不了20ms.
在寫查詢的時候,要自己寫一個方法,強制從數據庫取數據,因為這個時候Cache里的pic那個值也已經被修改了.
所以這里,就有了樓主項目里的一段代碼
FindByIDFromDb是樓主重寫的一個方法,目的是避免從Cache中查找數據,其實就是把下面這樣的代碼中,if去掉,else及后面的語句去掉,只留FindAll(_.CompanID,CompanyID)這個方法,就從數據庫下SQL查找了
本節到此結束,下一節我們講一下復雜查詢,可能會分2節來講,一節講復雜查詢如何實現,一節講一講大石頭引以為豪的萬億級 數據量分頁(樓主就是被這個性能所吸引過來的~~)
萬億級數據量分頁 大石頭說這個有人超越他就請客吃飯的哦~~~
本節Demo(基本沒有寫代碼,所以...不過還是奉上Demo吧)
http://dl.dbank.com/c0672sbtuj
ps:本節代碼折疊了哦~~~想要的到論壇上搜索"折疊"就能找到
XCode上手指南系列:
NewLife.XCode 上手指南
NewLife.XCode 上手指南(二) 反向工程使用舉例
NewLife.Xcode 上手指南(三) 擴展屬性的使用
NewLife論壇地址:
大石頭博客:
NewLife.XCode開發資源目錄
http://www.cnblogs.com/asxinyu/archive/2012/06/02/2532210.html