首先,ADO.NET中使用了DataAdapter 來處理與資料庫的聯機與離線。當時開發人員設計了DataAdapter是為了能夠處理離線資料,方便操作,關於這一點,只要調用其Fill()方法即可,這時會在DataSet中建立一個新的名為“Table“的DataTable.要重新指定名可用DataAdapter.Fill(DataSet,“Tabelname“)。此時connection也關閉了。DataAdapter既可以用來提交查詢,並將結果儲存到DataSet中,也可以用來向資料庫傳遞更改。僅僅使用其Update方法即可達到向資料庫提交儲存地DatSet中的更改。
DataAdapter將查詢的結果儲存在DataSet或DataTable對象中,當執行這一過程的時候,DataAdapter使用了一個Command來與資料庫通訊,並在內部使用了DataReader來擷取查詢結果,最後才將結果複製到DataSet新行中去。這也是Fill的過程。如果有兩個DataAdapter對象,都使用相同的Connection對象,在建立的時候就會建立兩個Connection對象,而不是同一個,這種情況的解決方案是:
SqlConnection con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;")
SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Categories",con);
SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Customers",con);
而不是將查詢字串,單獨寫成一行。
有時候可能並不希望DataSet中的架構與資料庫中的架構相同,這種情況的解決方案之一是可以採用別名的方法,即select id as Product ID,amount as Product Amount from product;另外一種解決方案就是使用DataAdapter提供的TableMappings集合機制,通過它就可以將查詢結果映射到DataSet結構中,這種方法更方便,更靈活。TableMappings屬性返回一個DataTableMappingsCollection對象,其中包含了一組DataTableMappings,只要DataSet中相應的表名稱與資料庫中的表名相同,即可以使用它來建立一個映射(DataSet中可以有多個表)。TableMappings裡還有一個ColumnMappings屬性,其用法與TableMappings相似。其原理是DataAdapter從資料庫讀取資料後,利用DataReader從結果集中擷取列名稱,有一點特別要注意,即只能擷取列名稱而無法擷取表名稱,DataAdapter事先假定表名稱為Table,接著遇到映射語句則進行表映射。不說了,看代碼:
DataColumnMapping colMap;
SqlConnection con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;");
SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Categories",con);
DataSet ds=new DataSet();
DataTableMapping tblMap=da.TableMappings.Add("Table","Ca"); //這裡Table為關鍵,映射表名為Ca
colMap=tblMap.ColumnMappings.Add("CategoryID","ID"); //映射列表
colMap=tblMap.ColumnMappings.Add("Description","描述");
// Response.Write(tblMap.DataSetTable.ToString());
da.Fill(ds);
DataTable dt=ds.Tables["Ca"]; //這裡是映射後的表名,如果仍為資料庫的表名,則無效,特別注意
this.DataGrid1.DataSource=dt;
this.DataGrid1.DataBind();
運行代碼後就會發現DataGrid1上的列名為ID和描述 (^_^)
(註:使用DataTableMapping 之前要前置入名空間System.Data.Common;)
還可以使用AddRange方法來簡化表和列的映射:(一些代碼同上面)
.......
DataTableMapping tblMap=da.TableMappings.Add("Table","Ca"); DataColumnMapping[] colMapArray=new DataColumnMapping[]{new DataColumnMapping("CategoryID","產 品號"),new DataColumnMapping("Description","描述")}; tblMap.ColumnMappings.AddRange(colMapArray);
......
這種映射關係只能從資料庫中讀取展示給使用者,如果要將映射後的Table的更改提交給資料庫,這時庫發現其中列與庫中列不同,便會發生異常,DataAdapter 同時也提供了MissingMappingAction屬性來處理。
DataAdapter1.MissingMappingAction=MissingMappingAction.Passthrough/Ignore/Error
它接受MissingMappingAction的枚舉值,Passthrough這個值表示如果在庫中找不到與DataSet中相同列的話,就將此列映射到庫中,Ignore枚舉值表示忽略示出現的列,Error表示找不到相應的列則拋出異常。
分頁:
分頁在應用中是常有的事,而DataAdapter本身也提供了分頁的簡易功能,如:DataAdapter1.Fill(dataset,startrow,rownum,“tablename“)這種功能用於資料量較小的查詢就可以,但當有大量資料的時候,就會發現這種分頁的問題的存在。它的原理是假如有一百行資料,分成十頁,每頁十行,當擷取每一頁的時候,返回前10行,再接著,第二頁,刪除了前10行而擷取接下的10行,在這一次中,只是為了擷取10行資料,但資料庫卻返回了20行,依此類推,第10頁的時候就會返回100行,而DataAdapter本身就幫我們刪除了90行,因為我們看上去返回的還是10行,這種效能太低。因此本篇繼續介紹另外一種效能較高的分頁方法。實際上這種分頁方法是將上一頁最後一行的KVStore for Redis下來,直接在SQL語句中就過濾掉了,不象前面那種到DataAdapter這邊才過濾掉。例:
con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;");
da=new SqlDataAdapter("select top 50 CustomerID,CompanyName from Customers where CustomerID>'BOTTM'",con);
ds=new DataSet();
da.Fill(ds,"Categories");
this.DataGrid1.DataSource=ds.Tables["Categories"]; this.DataGrid1.DataBind();
con.Close();
這裡假如上一頁最後一個索引值為”BOTTM”,可以將它用參數替代掉,這樣就查出了在'BOTTM'之後的50行。這種方法實現簡單效率也高。