你的程式裡,是否到處充斥著這種程式碼:
db.Customers.InsertOnSubmit(customer);
db.SubmitChange();
如果某一天,因為 Customers 表的資料庫巨增,需要把它拆成兩個表,你是否會膽寒???當然,對於查詢,我們可以通過檢視來解決。對於插入,或者更新呢?據說,現在的資料庫在某些情況下,可以對檢視進行資料的更新、插入。但是我們要考慮的是不可以的情況。是不是得每個地方都改呀?對於一個大型的專案,這種改動是很可怕的,某個地方少改了,就糟糕了。不過,對於這種情況,Linq to SQL早已經為我們想好了應對的方案。實現 DataContext 繼承類中的 InsertCustomer(Customer customer) 方法就可以了,如下圖所示。
實現方法的虛擬碼:
partial void InsertCustomer(Customer instance) { //往表1插入資料
//往表2插入資料 }
當實現了 InsertCustomer 這個方法,Linq to SQL 再往 Customers 這個表插入資料時,將會呼叫該方法來插入資料,而不是預設的方式。
稍微注意一下,我們發現還有 UpdateCustomer,DeleteCustomer 這兩個方法,估計你們也能猜到它們的用途了,沒錯,就是用來替換掉預設的更新、刪除方法。
我們現在接著來考慮一個問題,Linq to SQL 是如何得知 InsertCustomer、UpdateCustomer 和 DeleteCustomer 這幾個方法已經實現了呢?通過反射。那我們現在大慨可以得知,Linq to SQL 在插入、更新、刪除資料是這麼一個過程:
先通過反射,看是否存在 InsertCustomer、UpdateCustomer、DeleteCustomer 這些方法是否存在,如果存在,則呼叫這些方法,否則採用預設的方法進行增刪改。但是,這樣會有一個問題,如果插入10條資料,則需要呼叫反射方法10次,這未免有點笨,眾所周知,反射是比較耗效能,而且,這是不必要的效能損失。所以 Linq to SQL 在通過反射把那幾個方法找出來後,快取起來,重複使用。那麼,這幾個方法是快取在哪裡呢?
在 MetaTable 這個類裡面,我們可以看到 InsertMethod、 UpdateMethod 和 DeleteMethod 這三個屬性。沒錯,增刪改的擴充套件方法,就是快取這裡。
我們現在再來理清一下這個流程:
1、在建立 DataContext 的時候,會建立一個影射源(MappingSource)。該影射源會針對每個類,建立一個元表(MetaTable),用來描述表與實體之間的影射。在建立這個元表的時候,通過反射,檢查 DataContext 是否有對應實體類的增刪改的擴充套件方法,如果有,則為 InsertMethod、UpdateMethod、DeleteMethod 這三個屬性相應地賦值。
2、在插入一條數的時候的時候,先把該實體類對應的元表找出來,看該元表的 Insert 屬性是否為空(null),如果為空,則呼叫預設的插入方法,該方法等價於 DataContext 類中的 ExecuteDynamicInsert 方法。
Linq to SQL 對資料增刪改的流程,就是這麼個樣。