對比.NET PetShop和Duwamish來探討Ado.NET的資料庫編程模式

來源:互聯網
上載者:User
ado|編程|資料|資料庫   對比.NET PetShop和Duwamish來探討Ado.NET的資料庫編程模式概述Ado.NET為我們提供了強大的資料庫開發能力,它內建的多個對象為我們的資料庫編程提供了不同的選擇。但是在允許我們靈活選用的同時,許多初學者也很迷惑,我到底是應該使用DataReader還是應該使用DataAdapter?我只想讀取一小部分資料,難道我一定要Fill滿整個DataSet嗎?為什麼DataReader不能和RecordSet一樣提供一個資料更新的方法?DataSet到底有什麼好處?在本文中,我將對.NET PetShop的資料庫編程模式和Duwamish的資料庫編程模式進行一些簡單的分析和對比。如果您也有以上疑問的話,相信在讀完本文之後,就可以根據具體的需要來制定一個最適合您應用的資料庫編程模式。目錄
  • .NET PetShop和Duwamish簡單介紹
  • 結構簡述
  • Duwamish資料訪問剖析
  • .NET PetShop資料訪問剖析
  • 分析總結
.NET PetShop和Duwamish簡單介紹相信大家一定聽說過有名的"寵物店大戰",沒錯,本文的主角之一就是獲勝方.NET PetShop,微軟號稱以27倍的速度和1/4的代碼量遙遙領先於基於J2EE的PetStore寵物商店。雖然SUN也曾對此抱怨過不滿,指責此"大戰"有水分,不過無論如何,.NET PetShop絕對是一個經典的.NET執行個體教程,至少為我們提供了一條趕超J2EE的“捷徑” :),它的下載地址是:http://www.gotdotnet.com/team/compare
.NET PetShop寵物網上商店首頁而Duwamish則是一個外表簡單,內部卻極其複雜的一個網上書店的.NET完整應用範例,作為一個微軟官方的Sample,它同時提供了C#和VB.NET兩種語言版本,並且還附上了大量詳盡的中文資料,如果列印出來,實在是居家旅行,臨睡入廁必備之物。什嗎?您沒聽說過?呵呵,如果您裝了Visual Studio .NET的話,它就在您的硬碟上靜靜的躺著呢,不過還沒有被安裝,您可以在您的VS.NET 的Enterprise Samples目錄下找到並安裝它,例如:C:\Program Files\Microsoft Visual Studio .NET\Enterprise Samples\Duwamish 7.0 CS。
Duwamish網上電子書店首頁結構簡述兩家商店都採用了n層應用結構(毫無疑問,n層結構的應用架構應該絕對是您開發.NET應用的首選,哪怕您只想做一個網頁計數器),不同的是,PetShop採用的是最常見的三層應用結構,分別為展示層,中介層和資料層。而Duwamish則採用的是一個四層應用結構,並使用不同的項目分隔開,分別為展示層,業務外觀層,商務規則層和資料層。至於這兩種結構分別有什麼優點和缺點,以及為什麼要這麼分層,我們不進行詳細討論,因為本文的重點不在於此。我們主要分析的是他們的資料庫編程的模式。Duwamish資料訪問剖析首先,我們來看看Duwamish書店,它採用的是DataAdapter和DataSet配合的資料存放區模式,所不同的是,它對DataSet進行子類化擴充作為資料載體,也就是採用定製的DataSet來進行層間的資料轉送,下面是一個定製的DataSet樣本:
public class BookData : DataSet{  public BookData()  {       //       // Create the tables in the dataset       //       BuildDataTables();  }  private void BuildDataTables()  {        //        // Create the Books table        //        DataTable table   = new DataTable(BOOKS_TABLE);        DataColumnCollection columns = table.Columns;                columns.Add(PKID_FIELD, typeof(System.Int32));        columns.Add(TYPE_ID_FIELD, typeof(System.Int32));        columns.Add(PUBLISHER_ID_FIELD, typeof(System.Int32));        columns.Add(PUBLICATION_YEAR_FIELD, typeof(System.Int16));        columns.Add(ISBN_FIELD, typeof(System.String));        columns.Add(IMAGE_FILE_SPEC_FIELD, typeof(System.String));        columns.Add(TITLE_FIELD, typeof(System.String));        columns.Add(DESCRIPTION_FIELD, typeof(System.String));        columns.Add(UNIT_PRICE_FIELD, typeof(System.Decimal));        columns.Add(UNIT_COST_FIELD, typeof(System.Decimal));        columns.Add(ITEM_TYPE_FIELD, typeof(System.String));        columns.Add(PUBLISHER_NAME_FIELD, typeof(System.String));        this.Tables.Add(table);  }………}
我們可以看到它有一個BuildDataTables方法,並且在建構函式中調用,這樣,定製的Books表就和這個DataSet捆綁在一起了,省得以後還要進行Column Mapping,這真是個好主意,我怎麼就沒有想到呢? :)解決了資料結構,接下來看看資料層的代碼實現,在Duwamish中,資料層中有5個類,分別是Books,Categories,Customers和Orders,每個類分別只負責有關資料的存取。下面是其中一個類的範例程式碼:
private SqlDataAdapter dsCommand;public BookData GetBookById(int bookId){    return FillBookData("GetBookById", "@BookId", bookId.ToString());}private BookData FillBookData(String commandText, String paramName, String paramValue){    if (dsCommand == null )    {        throw new System.ObjectDisposedException( GetType().FullName );    }                BookData   data    = new BookData();    SqlCommand command = dsCommand.SelectCommand;    command.CommandText = commandText;    command.CommandType = CommandType.StoredProcedure; // use stored proc for perf    SqlParameter param = new SqlParameter(paramName, SqlDbType.NVarChar, 255);    param.Value = paramValue;    command.Parameters.Add(param);                dsCommand.Fill(data);    return data;}
這裡就是資料層的代碼了,我們在這裡可以看到Duwamish採用了DataAdapter來將資料填充到定製的DataSet中,然後返回該DataSet。我感到很奇怪的是在資料存取層中竟然可以看到GetBookById這樣具體的資料存取方法,雖然最後還是有一個抽象出來的FillBookData方法,但是上面還有三層啊,底層都做到這份上了,那上層都做些什麼呢?答案是資料檢查,上層基本上都在做一些很嚴密的資料合法性校正(當然也會包括一些比較複雜的事務邏輯,但是並不多),範例程式碼如下:
public CustomerData GetCustomerByEmail(String emailAddress, String password){    //    // Check preconditions    //    ApplicationAssert.CheckCondition(emailAddress != String.Empty, "Email address is required",ApplicationAssert.LineNumber);    ApplicationAssert.CheckCondition(password != String.Empty, "Password is required", ApplicationAssert.LineNumber);    //    // Get the customer dataSet    //    CustomerData dataSet;    using (DataAccess.Customers customersDataAccess = new DataAccess.Customers())    {dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);    }    //        // Verify the customer's password    //    DataRowCollection rows = dataSet.Tables[CustomerData.CUSTOMERS_TABLE].Rows;    if ( ( rows.Count == 1 ) && rows[0][CustomerData.PASSWORD_FIELD].Equals(password) )    {        return dataSet;    }    else    {        return null;    }}
在這個方法中,真正進行資料存取的實際上只有
dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);
這麼一句,是直接調用的資料層。其它都是在進行合法性校正,我們可以感悟到,進行一個真正的企業級開發需要考慮的系統健壯性有多麼重要。.NET PetShop資料訪問剖析OK,Duwamish看完了,下面我們來看看PetShop的資料訪問機制。PetShop只有一個項目,它採用的分層辦法是將中介層和資料層都寫成cs檔案放在Components目錄裡,其中資料層就是一個名為Database的類,它封裝了所有對資料庫的底層操作。下面是範例程式碼段:
public void RunProc(string procName, out SqlDataReader dataReader) {SqlCommand cmd = CreateCommand(procName, null);dataReader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);}
我們看到了一個跟Duwamish截然不同的另一種資料訪問方式,它將所有的資料存取方法抽象出來做成一個RunProc方法,至於返回資料呢,呵呵,它有點偷懶,直接返回一個DataReader給你,你自己去讀吧。還記得Duwamish採用的層間資料轉送載體是什麼嗎?對了,是DataSet,它被資料層填充後返回給了中介層。但是這裡,資料層和傳輸層的資料轉送載體變成了DataReader,實際上,還不能稱它為資料載體,因為資料還沒開始讀呢,在這裡,DataReader的作用和指標有點類似,也許我們應該稱它為“資料引用”:)接著往下看,DataReader被怎麼“處理”的:
public ProductResults[] GetList(string catid, int currentPage, int pageSize, ref int numResults) {numResults = 0;int index=0;SqlDataReader reader = GetList(catid);ProductResults[] results = new ProductResults[pageSize];// now loop through the list and pull out items of the specified pageint start = (int)((currentPage - 1) * pageSize);if (start <= 0) start = 1;// skip for (int i = 0; i < start - 1; i++) {if (reader.Read()) numResults++;}if (start > 1) reader.Read();// read the data we are interested inwhile (reader.Read()) {if (index < pageSize) {results[index] = new ProductResults();results[index].productid = reader.GetString(0);results[index].name =  reader.GetString(1);index++;}numResults++;   }reader.Close();// see if need to redim arrayif (index == pageSize)return results;else {// not a full page, redim arrayProductResults[] results2 = new ProductResults[index];Array.Copy(results, results2, index);return results2;}}
注意到currentPage和pageSize了嗎?原來在這裡就進行了資料分頁,只返回滿足需要的最少的資料量,而不是象我們很多喜歡偷懶的人一樣,簡單的將整個DataTable一股腦的綁定到DataGrid,造成大量的資料冗餘。在這裡,資料被真正的讀出來,並且被手動填充到一個自訂的對象數組中,我們來看看這個數組的定義:
public class ProductResults {private string m_productid;private string m_name;// product propspublic string productid {get { return m_productid; }set { m_productid = value; }  }public string name {get { return m_name; }set { m_name = value; }  }}
非常之簡單,不過我有點奇怪為什麼不使用struct呢?是不是.NET中struct和class的效能差距已經可以忽略不計了?分析總結通過觀察這兩個商店的具體實現,我們得到了兩個不同的資料訪問模式,Duwamish採用的是以DataSet為核心,因為DataSet提供了這方面大量的相關方法,所以整個應用的資料轉送,資料格式定義,資料校正都圍繞著DataSet來進行,整個架構定義非常清晰和嚴謹,但是卻顯得有些龐大。PetShop在整個程式中沒有採用一個DataSet,程式非常的簡潔,輕靈,但是沒有Duwamish那麼強的健壯性。這兩個程式是Microsoft公司不同的小組寫出來的代碼,所以有著不同風格。不過都應該能代表.NET的標準模式。看到這裡,你應該對文章開頭提出的那些疑問有一個比較形象的認識了吧。另外,請再次注意,PetShop在開啟資料連線之後,並沒有馬上讀取資料,而是將DataReader傳遞給另外的對象來執行資料讀的操作,然後才關閉串連。這樣,資料連線的時間加長了,而資料庫連接是一項非常寶貴的伺服器資源,相比之下,Dawamish在串連資料庫之後馬上進行填充,然後迅速釋放掉資料庫連接的方式更加有利於大量使用者的並發訪問。再一點,上文的程式中沒有提到更新操作,PetShop採用的是使用Command對象執行單個預存程序的方式來進行更新操作,是屬於一種線上即時資料更新模式。而Dawamish採用的是DataAdapter的Update方法,將DataSet的改變一次性的提交到資料庫中,屬於離線資料更新模式。這種模式的好處是可以一次性更新大批量資料,減少資料庫的串連次數。缺點是如果資料庫在改動非常頻繁的情況下需要即時的跟蹤資料變化就不合適了。需要根據具體的情況採用具體的資料更新辦法。總的來說,如果您只需要快速的讀取資料並顯示出來,推薦您採用DataReader,如果您需要對資料進行大量的修改,還有大量並發訪問的可能,而且不需要即時的追蹤資料庫的變化,推薦您使用DataSet。當然,這兩種情況有點極端了,實際的應用環境也許有著很複雜的條件,具體需要您自己審時度勢,綜合採用,不過我個人還是比較喜歡PetShop那種輕靈的風格 :)


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。