怎樣在ASP.NET項(xiàng)目里面正確使用Linq to Sql_.Net教程
推薦:解讀鏈表的順序表示和實(shí)現(xiàn)/*List.h*/ #ifndef _LIST_H #define _LIST_H #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 template
Linq to Sql 用的人也應(yīng)該有些吧,我在cnblogs上面看老趙寫的那幾篇文章(請看08年9月左右的文章),感覺也很有深度,有不少啟發(fā)。因此我也打算寫一點(diǎn)我自己的實(shí)踐經(jīng)驗(yàn),希望也能同樣給大家一些有用的啟發(fā)吧。
我首先想要問一下大家,Linq to Sql有哪些很特別的地方?這個(gè)問題的答案肯定五花八門,我說一下我看到的一些問題吧。
首先,Linq to Sql的基礎(chǔ)之一是DataContext,而另外一個(gè)基礎(chǔ),則是通過映射產(chǎn)生的實(shí)體類,以及這些實(shí)體類的Table<>對(duì)象。這個(gè)不是廢話嘛!我想很多人都應(yīng)該知道這個(gè)最基本的知識(shí),不過卻不見得有多少人真正注意到,或者認(rèn)真思考一下這里面的“機(jī)關(guān)”。不知道“機(jī)關(guān)”在哪里,那么就不可能寫出合適的代碼。比如說,在某個(gè)頁面里面(N層結(jié)構(gòu)沒有給弄好的情況下),或者在某個(gè)業(yè)務(wù)邏輯里面(有N層結(jié)構(gòu)),你的Linq to Sql的代碼是否是長這樣的?
以下為引用的內(nèi)容: using (MyDataContext db = new MyDataContext) |
“對(duì)啊,就是長這樣的,有什么問題嗎?”當(dāng)然有問題啦,否則我也不寫這個(gè)隨筆了。不知道大家有沒有想過這么一個(gè)問題,什么叫做Context?Context就是上下文,上下文的意思就是,依賴于這個(gè)上下文的對(duì)象,必須存活在這個(gè)上下文里面。脫離了這個(gè)上下文,那些對(duì)象就會(huì)出現(xiàn)錯(cuò)誤。事實(shí)上也確實(shí)如此:在上面的例子里面,從ProductInfos中得到的q.ToList(),里面的每一個(gè)元素都依賴于MyDataContext。換句話說MyDataContext如果被注銷了,q.ToList()生成的對(duì)象也就會(huì)“部分功能失效”。
“失效就失效好了,反正該做的工作已經(jīng)做完了,q.ToList()也已經(jīng)利用完了。”不錯(cuò),在上面的例子里面,不會(huì)發(fā)生什么錯(cuò)誤。不過這么寫的話,會(huì)比較難使用的。為什么這么說?我舉一個(gè)具體的例子:這個(gè)網(wǎng)站需要用戶登錄,而所有的業(yè)務(wù)邏輯幾乎都依賴于當(dāng)前用戶。如果說,我們使用上面的using模式,那么我估計(jì)你的代碼不外乎是如下兩種情況:
1、每一次需要當(dāng)前用戶的地方,你都需要從數(shù)據(jù)庫讀取;或者
2、你把當(dāng)前用戶保存為全局變量了,但是你發(fā)現(xiàn)currentUser.CompanyInfo因?yàn)樯舷挛囊呀?jīng)拋棄了,因此是無法使用的,業(yè)務(wù)層不得不每一次都重新從數(shù)據(jù)庫讀取該用戶所屬公司的數(shù)據(jù)。
這兩種形式如下所示:
以下為引用的內(nèi)容: // 通過實(shí)體對(duì)象來存儲(chǔ) |
如果你是第一種情況,那么很明顯,你會(huì)有大量重復(fù)的SQL調(diào)用。
如果是第二種情況,其實(shí)也不見得好到哪里去。因?yàn)椋?/p>
1、currentUser可能不需要經(jīng)常取,但相關(guān)的其它內(nèi)容,由于上下文各自獨(dú)立,你還是經(jīng)常在重復(fù)的獲取的;
2、有一個(gè)地方你無法繞過去——如果你要修改當(dāng)前用戶的屬性,而這個(gè)全局的當(dāng)前用戶不是當(dāng)前Context產(chǎn)生的,你還非得從當(dāng)前Context取出來,然后再修改;
3、因?yàn)閏urrentUser的上下文已經(jīng)被拋棄了,因此程序會(huì)很容易設(shè)計(jì)成傳入的不是一個(gè)UserInfo,而是一個(gè)int類型的Id值,否則底層很容易一不小心就用到這個(gè)實(shí)際上功能不全的對(duì)象,然后就拋出異常了。但這樣做的后果是,獲取同一個(gè)類型的實(shí)體對(duì)象,可能會(huì)有各種不同的重載形式,例如:
以下為引用的內(nèi)容: IQueryable<TransactionInfo> GetTransactionsByUserId(int userId); |
因?yàn)檫@種設(shè)計(jì)實(shí)施之后,有時(shí)很可能就會(huì)出現(xiàn)只有userId的情況,那么這個(gè)時(shí)候即使UserInfo對(duì)象中其實(shí)也存在CompanyId的值,也還是要重新獲取一遍UserInfo對(duì)象。為了簡化這一過程,就可能會(huì)產(chǎn)生不同的獲取形式。
這樣設(shè)計(jì)完整個(gè)系統(tǒng)之后一跑,看著好像沒什么,但真正上線卻發(fā)現(xiàn)有點(diǎn)慢。當(dāng)我們打開Sql server的Profiler一看,會(huì)發(fā)現(xiàn)很簡單的一個(gè)頁面的訪問,其數(shù)據(jù)庫訪問會(huì)搞到幾十次甚至上百次,其中有很多Sql語句是完全重復(fù)的。
這個(gè)問題怎么解決呢?有人會(huì)說,加個(gè)緩存機(jī)制吧。也許吧,但這種增加復(fù)雜度的設(shè)計(jì),我覺得還是不得已而為之的一種做法。我認(rèn)為更好的解決辦法是,將上下文在當(dāng)前頁面中緩存起來。所謂的上下文,就是一種運(yùn)行環(huán)境,而一次頁面訪問,其環(huán)境應(yīng)該是相同的。首先,我們對(duì)MyDataContext做一個(gè)擴(kuò)展:
以下為引用的內(nèi)容: partial class MyDataContext |
然后我們再制作一個(gè)HttpModule(并且在web.config里面配置好):
以下為引用的內(nèi)容: /// <summary> |
接下來,我們只要在邏輯層這么直接寫即可:
以下為引用的內(nèi)容: public static IQueryable<TransactionInfo> GetCompanyAccountDetails(UserInfo operatorUser, EAccountName account) |
這么改造完之后,你會(huì)發(fā)現(xiàn)幾乎可以在所有地方直接返回IQueryable(除了有的時(shí)候Linq to Sql本身有Bug),整個(gè)邏輯層內(nèi)的設(shè)計(jì)變得簡單化:一開始檢查各種參數(shù)(是否具備完整或者部分權(quán)限),然后根據(jù)檢查結(jié)果做完全信賴的操作。由于返回的是實(shí)體對(duì)象,或者IQueryable,幾乎所有重復(fù)性的Sql調(diào)用也隨之自然消失了。如果有所懷疑的話,您可以用Sql Profiler自行做修改前后的對(duì)比,看看效果是否“驚人”?
也許有人會(huì)質(zhì)疑,這樣好嗎?豈不是通過user.Company.Transactions就可以得到所有的Transaction了?沒錯(cuò),如果所有東西都是公開的話,就會(huì)有這個(gè)問題。如果要徹底解決這樣的問題,需要將這些部分變成對(duì)邏輯層可見,而對(duì)其它層不可見的修飾方式——比如兩層在一個(gè)dll里面,這些屬性是internal的,或者放在兩個(gè)dll里面并且打上InternalsVisibleTo標(biāo)記。通過這種方式,就可以避免上層直接查找DAL中一些在BLL中需要經(jīng)過權(quán)限檢查才可以得到的內(nèi)容。當(dāng)然,如果項(xiàng)目比較小的情況下,你也可以選擇不要這么麻煩,直接控制代碼質(zhì)量即可(要求有些東西必須通過BLL來獲得)。
分享:淺談ASP.NET中顯示Linq To SQL輸出的SQL語句最近在使用Linq To SQL的時(shí)候,為了了解不同Linq語句對(duì)性能造成的不同影響,需要獲得Linq To SQL生成的SQL語句。 如果是在桌面程序中,只需要 _context.Log = Console.Out; 即可在控制臺(tái)輸出SQL語句。可是在ASP.NET中又該怎么辦呢? 這時(shí)我想起了StringWriter
- asp.net如何得到GRIDVIEW中某行某列值的方法
- .net SMTP發(fā)送Email實(shí)例(可帶附件)
- js實(shí)現(xiàn)廣告漂浮效果的小例子
- asp.net Repeater 數(shù)據(jù)綁定的具體實(shí)現(xiàn)
- Asp.Net 無刷新文件上傳并顯示進(jìn)度條的實(shí)現(xiàn)方法及思路
- Asp.net獲取客戶端IP常見代碼存在的偽造IP問題探討
- VS2010 水晶報(bào)表的使用方法
- ASP.NET中操作SQL數(shù)據(jù)庫(連接字符串的配置及獲取)
- asp.net頁面?zhèn)髦禍y試實(shí)例代碼
- DataGridView - DataGridViewCheckBoxCell的使用介紹
- asp.net中javascript的引用(直接引入和間接引入)
- 三層+存儲(chǔ)過程實(shí)現(xiàn)分頁示例代碼
.Net教程Rss訂閱編程教程搜索
.Net教程推薦
- ASP.NET 2.0中動(dòng)態(tài)修改頁面標(biāo)題
- String.Empty、NULL、“”的不同之處
- ASP.NET 2.0當(dāng)中的Call Back機(jī)制
- 解決ASP.NET中讓網(wǎng)頁彈出窗口的問題
- datagrid綁定list沒有數(shù)據(jù) 表頭不顯示的解決方法
- 在ASP.NET中使用AJAX的簡單方法
- 解讀.Net技術(shù)開發(fā)中兩個(gè)“屬性”引起的歧異
- .net中string無重復(fù)數(shù)字的實(shí)現(xiàn)方法
- .NET:InTheHand提供的類操作SMS
- asp.net將Execl讀到DataSet或DataTable中
- 相關(guān)鏈接:
- 教程說明:
.Net教程-怎樣在ASP.NET項(xiàng)目里面正確使用Linq to Sql。