關於Ado.Net Entity Framework 的理論、入門教學文章已不少了,但是很少有人講到在ASP.Net項目中實際項目應用的問題,往往學的時候輕松搞定,一上手項目就一頭霧水。
比如在教程中最常見的這種形式的使用方法:
using(MyObjectContext c=new MyObjectContext())
{
……
}
如果在實際應用中,每每需要連接數據庫,就造這麼一個代碼塊的話,那麼一個頁面訪問時就可能會創建數個數據庫連接,致使並發用戶訪問數大打折扣;
而假如只使用一個這樣的代碼塊的話,那麼由於分層、服務器控件、用戶控件等因素,又難以將所有數據庫訪問操作都揉到這一個代碼塊當中;
那麼到底該怎樣做才是最佳方案呢?
這個問題或許是Entity Framework的使用者產生疑惑最多的一點。
我在此將結合自己的經驗,解答包括上述問題在內的一些在ASP.Net實際項目中容易產生的疑問。
首先,我們需要搭建一個演示環境。
建立一個數據庫,並創建如下兩個表:
關系:Article的PostUser字段對應到User的ID字段
將兩個表分別填充一些數據:
生成Entity Framwork模型:
准備工作完成。
如果要擴展實體類的功能,應該通過“部分類”(partial)實現:
如果需要借助ObjectContext對象查詢或更新數據庫,應將ObjectContext定義為方法參數,而不是在業務邏輯層中創建ObjectContext對象。
例如,下面的方法不應該出現在業務邏輯層:
更好的做法是:
上圖中高亮的重載方法只應在需要時才編寫,通常都可予以忽略。
(方法中的統計總數的代碼語句完全可以由LinQ語句替代完成,並且非常精簡,而這裡只是象征性演示,別太在意)
這樣是從緩存中直接取出實體對象,效率非常高。
可通過CompiledQuery.Compile()預編譯查詢:
一般來說,一個頁面只需要一個數據庫連接,這樣可以減少數據庫的並發壓力,使同一時間可以有更多用戶訪問網站。
而通常情況下,我們都使用ObjectContext的無參構造函數創建包含默認連接的ObjectContext對象,因此,在同一頁面中共享一個ObjectContext就能實現同一頁面共享一個數據庫連接的目標。
接下來我們將在頁面中放置兩個EntityDataSource控件,分別獲取所有用戶及所有文章,並以ListView控件顯示出來。
同時還要放置一個用戶控件,用來獲取並顯示每個用戶曾發布的文章。
我們先來創建用戶控件界面:
用戶控件界面中僅包含一個ListView控件。
(為了簡單起見,ul中的li代碼將由後台生成,然後直接綁定到這裡)
接著是後台代碼:
注意,這裡定義了一個ObjectContext屬性,程序將通過該屬性訪問數據庫及業務邏輯層,但該屬性並未在這裡初始化,而是要由使用此用戶控件的頁面初始化該屬性。
接下來編寫頁面前台代碼:
簡單的放置並配置了兩個EntityDataSource及ListView,並放置了一個前面創建的用戶控件。
後台代碼:
這裡也同樣設置了一個ObjectContext屬性,並在藍色高亮處重寫了OnInit,在其中進行初始化,並賦值給用戶控件,然後在綠色高亮處重寫了Dispose,對ObjectContext進行釋放。
這樣用戶控件就將和頁面使用同一個ObjectContext對象了。
然而,每個EntityDataSource還都會自己創建ObjectContext連接數據庫,這顯然不合我們的期望,解決辦法是分別注冊它們的ContextCreating、ContextDisposing事件,做如下處理:
這樣頁面雖然多次在不同的位置訪問數據庫,但僅使用一個ObjectContext、一個數據庫連接。
執行結果:
EntityConnection即代表一個數據庫連接,可以通過創建EntityConnection對象,並將其分配給多個ObjectContext對象,實現多ObjectContext共享單連接,具體方法可參看MSDN:http://msdn.microsoft.com/zh-cn/library/bb738582.aspx
多ObjectContext共享一個連接,與整頁面共享一個ObjectContext有什麼不同呢?
一般來說感覺不到什麼不同,但當你將更改提交到數據庫時,單個ObjectContext將維護全部相關事務,一旦提交失敗將全部回滾,而多個ObjectContext就可以分別處理各自的事務,相比之下更具靈活性。
在這裡我僅以自己的經驗總結而出了一些問題和解決方案,若有其他疑問歡迎補充,共同探討。
針對上面的問題,如有更好的解決方案的話,也歡迎賜教。