ado.net最佳實踐

Ado.net最佳實踐

http://www.dotnetfamily.com/news/newsfiles/20066252228705.html

要通過應用程序執行以下操作,就要使用 DataSet

在結果的多個離散表之間進行導航。

操作來自多個數據源(例如,來自多個數據庫、一個 XML 文件和一個電子表格的混合數據)的數據。

在各層之間交換數據或使用 XML Web 服務。與 DataReader 不同的是,DataSet 能傳遞給遠程客戶端。

重用同樣的行組,以便通過緩存獲得性能改善(例如排序、搜索或篩選數據)。

每行執行大量處理。對使用 DataReader 返回的每一行進行擴展處理會延長服務於 DataReader 的連接的必要時間,這影響了性能。

使用 XML 操作對數據進行操作,例如可擴展樣式表語言轉換(XSLT 轉換)或 XPath 查詢。

對於下列情況,要在應用程序中使用 DataReader

不需要緩存數據。

要處理的結果集太大,內存中放不下。

一旦需要以只進、只讀方式快速訪問數據。

 

 

DataSet 中搜索數據

DataSet 中查詢與特定條件相匹配的行時,可以利用基於索引的查找提高搜索性能。當把 PrimaryKey 值賦給 DataTable 時,會創建一個索引。當給 DataTable 創建 DataView 時,也會創建一個索引。

如果對組成 DataTable PrimaryKey的列進行查詢,要使用 DataTable.Rows.Find 而不是 DataTable.Select

如果對組成 DataTable PrimaryKey的列進行查詢,要使用 DataTable.Rows.Find 而不是 DataTable.Select

對於涉及到非主鍵列的查詢,可以使用 DataView 爲數據的多個查詢提高性能。當把排序順序應用到 DataView 時,就會建立一個搜索時使用的索引。DataView 公開 Find FindRows 方法,以便查詢基礎 DataTable 中的數據。

如果不需要表的排序視圖,仍可以通過爲 DataTable 創建 DataView 來利用基於索引的查找。注意,只有對數據執行多個查詢操作時,這樣纔會帶來好處。如果只執行單一查詢,創建索引所需要的處理就會降低使用索引所帶來的性能提升。

 

批處理 SQL 語句

很多數據庫支持把多條命令合併或批處理成一條單一命令執行。例如,SQL Server 使您可以用分號 (;) 分隔命令。把多條命令合併成單一命令,能減少到服務器的行程數,並提高應用程序的性能。例如,可以把所有預定的刪除在應用程序中本地存儲起來,然後再發出一條批處理命令調用,從數據源刪除它們。

 

當訪問列數據時,使用類型化訪問器,例如,GetStringGetInt32 。這使您不用進行將 GetValue 返回的 Object 強制轉換成特定類型所需的處理。

例如:

[C#]
public void ReadMyData(string myConnString) {
string mySelectQuery = "SELECT OrderID, CustomerID FROM Orders";
OleDbConnection myConnection = new OleDbConnection(myConnString);
OleDbCommand myCommand = new OleDbCommand(mySelectQuery,myConnection);
myConnection.Open();
OleDbDataReader myReader;
myReader = myCommand.ExecuteReader();
// Always call Read before accessing data.
while (myReader.Read()) {
Console.WriteLine(myReader.GetInt32(0) + ", " + myReader.GetString(1));
}
// always call Close when done reading.
myReader.Close();
// Close the connection when done with it.
myConnection.Close();
}

默認情況下,DataReader 每次 Read 時都要把整行加載到內存。這允許在當前行內隨機訪問列。如果不需要這種隨機訪問,爲了提高性能,就把 CommandBehavior.SequentialAccess 傳遞給 ExecuteReader 調用。這將 DataReader 的默認行爲更改爲僅在請求時將數據加載到內存。注意,CommandBehavior.SequentialAccess 要求順序訪問返回的列。也就是說,一旦讀過返回的列,就不能再讀它的值了。

 

如果已經完成讀取來自 DataReader 的數據,但仍然有大量掛起的未讀結果,就在調用 DataReader Close 之前先調用 Command Cancel。調用 DataReader Close 會導致在關閉遊標之前檢索掛起的結果並清空流。調用 Command Cancel 會放棄服務器上的結果,這樣,DataReader 在關閉的時候就不必讀這些結果。如果要從 Command 返回輸出參數,還要調用 Cancel 放棄它們。如果需要讀取任何輸出參數,不要調用 Command Cancel,只要調用 DataReader Close 即可。

 

二進制大對象 (BLOB)

DataReader 檢索二進制大對象 (BLOB) 時,應該把 CommandBehavior.SequentialAccess 傳遞給 ExecuteReader 方法調用。因爲 DataReader 的默認行爲是每次 Read 都把整行加載到內存,又因爲 BLOB 值可能非常大,所以結果可能由於單個 BLOB 而使大量內存被用光。SequentialAccess DataReader 的行爲設置爲只加載請求的數據。然後還可以使用 GetBytes GetChars 控制每次加載多少數據。

記住,使用 SequentialAccess 時,不能不按順序訪問 DataReader 返回的不同字段。也就是說,如果查詢返回三列,其中第三列是 BLOB,並且想訪問前兩列中的數據,就必須在訪問 BLOB 數據之前先訪問第一列的值,然後訪問第二列的值。這是因爲現在數據是順序返回的,並且 DataReader 一旦讀過該數據,該數據就不再可用。

 

 

使用 SqlCommand 執行存儲過程的快速提示:如果調用存儲過程,將 SqlCommand CommandType 屬性指定爲 StoredProcedure CommandType。這樣通過將該命令顯式標識爲存儲過程,就不需要在執行之前分析命令 所以顯示指定命令類型是很有必要的。

 

測試 Null

如果表(在數據庫中)中的列允許爲空,就不能測試參數值是否等於空。相反,需要寫一個 WHERE 子句,測試列和參數是否都爲空。下面的 SQL 語句返回一些行,它們的 LastName 列等於賦給 @LastName 參數的值,或者 LastName 列和 @LastName 參數都爲空。

Null 作爲參數值傳遞

對數據庫的命令中,當把空值作爲參數值發送時,不能使用 nullVisual Basic .NET 中爲 Nothing)。而需要使用 DBNull.Value。例如:

 

 

 

 

}

 

 

 

 

 

對於 C# 程序員來說,確保始終關閉 Connection DataReader 對象的一個方便的方法就是使用 using 語句。using 語句在離開自己的作用範圍時,會自動調用被使用的對象的 Dispose。例如:

 

 

 

 

 

避免訪問 OleDbConnection.State 屬性

如果連接已經打開,OleDbConnection.State 屬性會對 DBPROP_CONNECTIONSTATUS 屬性的 DATASOURCEINFO 屬性集執行本地 OLE DB 調用 IDBProperties.GetProperties,這可能會導致對數據源的往返行程。也就是說,檢查 State 屬性的代價可能很高。所以僅在需要時檢查 State 屬性。如果需要經常檢查該屬性,監聽 OleDbConnection StateChange 事件可能會使應用程序的性能好一些。

 

 

 

 

 

避免自動增量值衝突

就像大多數數據源一樣,DataSet 使您可標識那些添加新行時自動對其值進行遞增的列。在 DataSet 中使用自動增量的列時,如果自動增量的列來自數據源,可避免添加到 DataSet 的行和添加到數據源的行之間本地編號衝突。

例如,考慮一個表,它的主鍵列 CustomerID 是自動增量的。兩個新的客戶信息行添加到表中,並接收到自動增量的 CustomerID 1 2。然後,只有第二個客戶行被傳遞給 DataAdapter 的方法 Update,新添加的行在數據源接收到一個自動增量的 CustomerID 1,與 DataSet 中的值 2 不匹配。當 DataAdapter 用返回值填充表中第二行時,就會出現約束衝突,因爲第一個客戶行已經使用了 CustomerID 1

要避免這種情況,建議在使用數據源上自動增量的列以及 DataSet 上自動增量的列時,把 DataSet 中的列創建爲 AutoIncrementStep 值等於 -1 並且 AutoIncrementSeed 值等於 0,另外,還要確保數據源生成的自動增量標識值從 1 開始,並且以正階值遞增。因此,DataSet 爲自動增量值生成負數,與數據源生成的正自動增量值不衝突。另外一個選擇是使用 Guid 類型的列,而不是自動增量的列。生成 Guid 值的算法應該永遠不會使數據源中生成的 Guid 值與 DataSet 中生成的 Guid 值一樣。

如果自動增量的列只是用作唯一值,而且沒有任何意義,就考慮使用 Guid 代替自動增量的列。它們是唯一的,並且避免了使用自動增量的列所必需的額外工作。

 

檢查開放式併發衝突

按照設計,由於 DataSet 是與數據源斷開的,所以,當多個客戶端在數據源上按照開放式併發模型更新數據時,需要確保應用程序避免衝突。

在測試開放式併發衝突時有幾項技術。一項技術涉及在表中包含時間戳列。另外一項技術是,驗證一行中所有列的原始值是否仍然與通過在 SQL 語句中使用 WHERE 子句進行測試時在數據庫中找到的值相匹配。

多線程編程

ADO.NET 對性能、吞吐量和可伸縮性進行優化。因此,ADO.NET 對象不鎖定資源,並且必須只用於單線程。一個例外是 DataSet,它對多個閱讀器是線程安全的。但是,在寫的時候需要把 DataSet 鎖定。

 



關於強類型dataset

使用強類型 DataSet 的好處

DataSet 的另一個好處是可被繼承以創建一個強類型 DataSet。強類型 DataSet 的好處包括設計時類型檢查,以及 Microsoft Visual Studio .NET 用於強類型 DataSet 語句結束所帶來的好處。修改了 DataSet 的架構或關係結構後,就可以創建一個強類型 DataSet,把行和列作爲對象的屬性公開,而不是作爲集合中的項公開。例如,不公開客戶表中行的姓名列,而公開 Customer 對象的 Name 屬性。類型化 DataSet DataSet 類派生,因此不會犧牲 DataSet 的任何功能。也就是說,類型化 DataSet 仍能遠程訪問,並作爲數據綁定控件(例如 DataGrid)的數據源提供。如果架構事先不可知,仍能受益於通用 DataSet 的功能,但卻不能受益於強類型 DataSet 的附加功能

處理強類型 DataSet 中的空引用

使用強類型 DataSet 時,可以批註 DataSet XML 架構定義語言 (XSD) 架構,以確保強類型 DataSet 正確處理空引用。nullValue 批註使您可用一個指定的值 String.Empty 代替 DBNull、保留空引用或引發異常。選擇哪個選項取決於應用程序的上下文。默認情況下,如果遇到空引用,就會引發異常。

 

 

以下不大明白

用架構填充 DataSet

當用數據填充 DataSet 時,DataAdapter.Fill 方法使用 DataSet 的現有架構,並使用從 SelectCommand 返回的數據填充它。如果在 DataSet 中沒有表名與要被填充的表名相匹配,Fill 方法就會創建一個表。默認情況下,Fill 僅定義列和列類型。

通過設置 DataAdapter MissingSchemaAction 屬性,可以重寫 Fill 的默認行爲。例如,要讓 Fill 創建一個表架構,並且還包括主鍵信息、唯一約束、列屬性、是否允許爲空、最大列長度、只讀列和自動增量的列,就要把 DataAdapter.MissingSchemaAction 指定爲 MissingSchemaAction.AddWithKey。或者,在調用 DataAdapter.Fill 前,可以調用 DataAdapter.FillSchema 來確保當填充 DataSet 時架構已到位。

FillSchema 的調用會產生一個到服務器的額外行程,用於檢索附加架構信息。爲了獲得最佳性能,需要在調用 Fill 之前指定 DataSet 的架構,或者設置 DataAdapter MissingSchemaAction

 

 

 
發佈了47 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章