在學(xué)習(xí)DataTable知識(shí)之前,我們有必要了解下ADO.NET。以下摘自MSDN:
ADO.NET 對(duì) Microsoft SQL Server 和 XML 等數(shù)據(jù)源以及通過 OLE DB 和 XML 公開的數(shù)據(jù)源提供一致的訪問。數(shù)據(jù)共享使用者應(yīng)用程序可以使用 ADO.NET 來連接到這些數(shù)據(jù)源,并檢索、處理和更新所包含的數(shù)據(jù)。
ADO.NET 通過數(shù)據(jù)處理將數(shù)據(jù)訪問分解為多個(gè)可以單獨(dú)使用或一前一后使用的不連續(xù)組件。ADO.NET 包含用于連接到數(shù)據(jù)庫(kù)、執(zhí)行命令和檢索結(jié)果的 .NET Framework 數(shù)據(jù)提供程序。您可以直接處理檢索到的結(jié)果,或?qū)⑵浞湃?ADO.NET DataSet 對(duì)象,以便與來自多個(gè)源的數(shù)據(jù)或在層之間進(jìn)行遠(yuǎn)程處理的數(shù)據(jù)組合在一起,以特殊方式向用戶公開。ADO.NET DataSet 對(duì)象也可以獨(dú)立于 .NET Framework 數(shù)據(jù)提供程序使用,以管理應(yīng)用程序本地的數(shù)據(jù)或源自 XML 的數(shù)據(jù)。
ADO.NET 類在 System.Data.dll 中,并且與 System.Xml.dll 中的 XML 類集成。當(dāng)編譯使用 System.Data 命名空間的代碼時(shí),請(qǐng)引用 System.Data.dll 和 System.Xml.dll。有關(guān)連接到數(shù)據(jù)庫(kù)、從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)并在命令提示中顯示該數(shù)據(jù)的 ADO.NET 應(yīng)用程序示例,請(qǐng)參見 ADO.NET 示例應(yīng)用程序。
ADO.NET 向編寫托管代碼的開發(fā)人員提供了類似于 ActiveX 數(shù)據(jù)對(duì)象 (ADO) 為本機(jī)組件對(duì)象模塊 (COM) 開發(fā)人員提供的功能。
ADO.NET中包含的對(duì)象及其關(guān)系如下圖:
1、DataTable簡(jiǎn)介
1.1 DataTable的定義
表示內(nèi)存中數(shù)據(jù)的一個(gè)表。 我們知道數(shù)據(jù)庫(kù)中存儲(chǔ)的是實(shí)體表,實(shí)體表中有一系列的數(shù)據(jù)。而DataTable即存儲(chǔ)在內(nèi)存中的表,在持久化到數(shù)據(jù)庫(kù)之前,是不會(huì)對(duì)數(shù)據(jù)庫(kù)產(chǎn)生影響的,持久化到數(shù)據(jù)庫(kù)可以使用dataAdapter.Update的方法(dataAdapter是某個(gè)實(shí)例化的DataAdapter對(duì)象)。
注意:當(dāng)訪問 DataTable 對(duì)象時(shí),請(qǐng)注意它們是按條件區(qū)分大小寫的。例如,如果一個(gè) DataTable 被命名為“mydatatable”,另一個(gè)被命名為“Mydatatable”,則用于搜索其中一個(gè)表的字符串被認(rèn)為是區(qū)分大小寫的。但是,如果“mydatatable”存在而“Mydatatable”不存在,則認(rèn)為該搜索字符串不區(qū)分大小寫。
1.2 得到DataTable
得到DataTable有許多方法,下面簡(jiǎn)單羅列出來:
1.2.1通過構(gòu)造函數(shù)得到DataTable
DataTable() 不帶參數(shù)初始化DataTable 類的新實(shí)例。
DataTable(string tableName) 用指定的表名初始化DataTable 類的新實(shí)例。
DataTable(string tableName, string tableNamespace) 用指定的表名和命名空間初始化DataTable 類的新實(shí)例。
1.2.2通過DataSet獲取DataTable
DataTable dt=ds.Tables["TableName"];//TableName是表名
1.2.3 通過DataRow自定義DataTable的結(jié)構(gòu)
DataTable dt= new DataTable("TB_USER");
DataColumn colUserID = new DataColumn("USER_ID", Type.GetType("System.Int"));
dt.Columns.Add(colCurrency);
DataColumn colUserName= new DataColumn("USER_NAME", Type.GetType("System.String"));
dt.Columns.Add(colUserName);
這樣得到是一個(gè)表的結(jié)構(gòu),里面沒有任何數(shù)據(jù),表面為TB_USER。
1.2.4通過已有的DataTable得到新的DataTable
可以使用DataTable.Clone()方法獲得現(xiàn)有DataTable的表的結(jié)構(gòu),這在實(shí)際中也是常用的
1.2.5通過DataAdapter填充DataTable
DataAdapter.Fill(dt);來填充DataTable,這也是新手常用的方法,通常是些sql語句,然后使用command,是最基礎(chǔ)的方法。
1.2.6通過DataRow數(shù)組導(dǎo)入DataTable
DataRow [] drs;//drs是某個(gè)有數(shù)據(jù)的DataRow數(shù)組
foreach(DataRow dr in drs)
{
dt.ImportRow(dr);
}
1.3 DataTable常用屬性
CaseSensitive 指示表中的字符串比較是否區(qū)分大小寫。
ChildRelations 獲取此DataTable 的子關(guān)系的集合。
Columns 獲取屬于該表的列的集合。
Constraints 獲取由該表維護(hù)的約束的集合。
DefaultView 獲取可能包括篩選視圖或游標(biāo)位置的表的自定義視圖。
HasErrors 獲取一個(gè)值,該值指示該表所屬的
DataSet 的任何表的任何行中是否有錯(cuò)誤。
MinimumCapacity 獲取或設(shè)置該表最初的起始大小。該表中行的最初起始大小。默認(rèn)值為 50。
Rows 獲取屬于該表的行的集合。
TableName 獲取或設(shè)置DataTable 的名稱。
1.4 DataTable是
ADO.NET中的重要成員
DataSet中可包括多個(gè) DataTable,可將多個(gè)查詢結(jié)構(gòu)存到一個(gè)DataSet中,方便操作,而DataTable中又包括多個(gè)DataRow、DataColumn,可通過這些DataRow、DataColumn來查看、操作其中的數(shù)據(jù),而需將操作結(jié)果返回給數(shù)據(jù)庫(kù)的話,則可以調(diào)用DataAdapter的 Update方法。
2、DataTable成員之DataRow
DataTable是由一個(gè)個(gè)DataRow組合而成,DataTable.Rows[i]即表示其中的第i行。
DataRow有一個(gè)十分重要的狀態(tài)(RowState),這個(gè)狀態(tài)經(jīng)常被我們忽略,從而導(dǎo)致一些莫名其妙的bug。RowState 的值是一個(gè)枚舉類型的,RowState 有 Added, Modified, Unchanged, Deleted, Detached 幾種, 分別表示 DataRow 被添加, 修改, 無變化, 刪除, 從表中脫離. 在調(diào)用一些方法或者進(jìn)行某些操作之后, 這些狀態(tài)可以相互轉(zhuǎn)化。我們不做什么判斷就開始操作DataRow,這就有可能導(dǎo)致某些狀態(tài)為Deleted的行也同時(shí)被操作,這樣就有可能導(dǎo)致臟數(shù)據(jù)的產(chǎn)生。
RowState 值
說明
Unchanged
自上次調(diào)用 AcceptChanges 之后,或自 DataAdapter.Fill 創(chuàng)建了行之后,未做出過任何更改。
Added
已將行添加到表中,但尚未調(diào)用 AcceptChanges。
Modified
已更改了行的某個(gè)元素。
Deleted
已將該行從表中刪除,并且尚未調(diào)用 AcceptChanges。
Detached
該行不屬于任何 DataRowCollection。新建行的 RowState 設(shè)置為 Detached。通過調(diào)用 Add 方法將新的 DataRow 添加到 DataRowCollection 之后,RowState 屬性的值設(shè)置為 Added。
對(duì)于已經(jīng)使用 Remove 方法(或是在使用 Delete 方法之后使用了 AcceptChanges 方法)從 DataRowCollection 中移除的行,也設(shè)置為 Detached。
3、DataTable成員之DataColumn
DataColumn 表示 DataTable 中列的架構(gòu)。
3.1 DataColumn中常見的熟悉及其說明如下:
屬性名
說明
Unique
設(shè)置DataColumn對(duì)象是否不允許重復(fù)的數(shù)據(jù)
Table
DataColumn對(duì)象所屬的DataTable對(duì)象
ReadOnly
DataColumn對(duì)象是否只讀
Ordinal
字段集合中的DataColumn對(duì)象順序
DefaultValue
DataColumn對(duì)象的默認(rèn)值
DataType
DataColumn對(duì)象數(shù)據(jù)類型
ColumnName
DataColumns集合對(duì)象中的字段名稱
Count
DataTable對(duì)象中的字段數(shù)
Caption
DataColumn對(duì)象的標(biāo)題
AutoIncrement
加入DataRow時(shí),是否自動(dòng)增加字段
AutoIncrementSeed
DataColumn對(duì)象的遞增種子
AllowDBNull
DataColumn對(duì)象是否接受Null值
3.2 DataColumn.Expression 表達(dá)式
獲取或設(shè)置表達(dá)式,用于篩選行、計(jì)算列中的值或創(chuàng)建聚合列。表達(dá)式的返回類型由列的 DataType 來確定。Expression 屬性的一個(gè)用途是創(chuàng)建計(jì)算出的列。例如,若要計(jì)算稅值,就要將單價(jià)乘以特定地區(qū)的稅率。由于各地稅率不同,不可能將單一稅率放在一個(gè)列中;于是便用 Expression 屬性來計(jì)算這個(gè)值,如下面這一部分中的 Visual Basic 代碼所示:DataSet1.Tables("Products").Columns("tax").Expression = "UnitPrice * 0.086"第二個(gè)用途是創(chuàng)建聚合列。類似于計(jì)算出的值,聚合基于 DataTable 中的整個(gè)行集執(zhí)行操作。一個(gè)簡(jiǎn)單的示例就是計(jì)算該集中返回的行數(shù)。這便是您將用來計(jì)算特定銷售人員所完成的交易數(shù)的方法,如下面的 Visual Basic 代碼所示:DataSet1.Tables("Orders").Columns("OrderCount").Expression = "Count(OrderID)";
表達(dá)式語法
在創(chuàng)建表達(dá)式時(shí),使用 ColumnName 屬性來引用列。例如,如果一個(gè)列的 ColumnName 是“UnitPrice”,而另一個(gè)是“Quantity”,則表達(dá)式將是:
"UnitPrice * Quantity"
4、DataTable成員之DataView
DataView類似數(shù)據(jù)庫(kù)中的視圖。
DataView 使您能夠創(chuàng)建 DataTable 中所存儲(chǔ)的數(shù)據(jù)的不同視圖,這種功能通常用于數(shù)據(jù)綁定應(yīng)用程序。使用 DataView,您可以使用不同排序順序顯示表中的數(shù)據(jù),并且可以按行狀態(tài)或基于篩選器表達(dá)式來篩選數(shù)據(jù)。
DataView 提供基礎(chǔ) DataTable 中的數(shù)據(jù)的動(dòng)態(tài)視圖:內(nèi)容、排序和成員關(guān)系會(huì)實(shí)時(shí)反映其更改。此行為不同于 DataTable 的 Select 方法,后者從表中按特定的篩選器和/或排序順序返回 DataRow 數(shù)組,雖然其內(nèi)容反映對(duì)基礎(chǔ)表的更改,但其成員關(guān)系和排序卻則保持靜態(tài)。DataView 的動(dòng)態(tài)功能使其成為數(shù)據(jù)綁定應(yīng)用程序的理想選擇。
與數(shù)據(jù)庫(kù)視圖類似,DataView 為您提供了可向其應(yīng)用不同排序和篩選條件的單個(gè)數(shù)據(jù)集的動(dòng)態(tài)視圖。但是,與數(shù)據(jù)庫(kù)視圖不同的是,DataView 不能作為表來對(duì)待,無法提供聯(lián)接的表的視圖。另外,還不能排除存在于源表中的列,也不能追加不存在于源表中的列(如計(jì)算列)。
在實(shí)際運(yùn)用中,我們時(shí)常使用如下代碼:
DataView dv = dt.DefaultView;
dv.Sort = "UserName"; //根據(jù)UserName排序,得到新的DataView
DataTable dtNew=dv.ToTable();//將DataView重新轉(zhuǎn)為DataTable
4.1 DataViewRowState:
其實(shí)DataView是類似于DataTable,它里面也有RowState,我們可以使用RowStateFilter來過濾不同狀態(tài)的行。
urrentRows包括所有未更新的、新的和修改的數(shù)據(jù)行
Deleted所有自上次調(diào)用AcceptChanges后刪除的數(shù)據(jù)行
ModifiedCurrent所有自上次調(diào)用AcceptChanges后修改過的數(shù)據(jù)行
ModifiedOriginal所有自上次調(diào)用AcceptChanges后original版本的數(shù)據(jù)行
New所有自上次調(diào)用AcceptChanges后新添加的行
OriginalRows返回初始數(shù)據(jù)行,包含unchanged和deleted 的
Unchanged所有未更新的數(shù)據(jù)行
4.2 DataView的過濾器
設(shè)置過濾 RowFilter是一個(gè)可讀寫的屬性,用來讀取和設(shè)置表過濾的表達(dá)式。public virtual string RowFilter {get; set;}
你可以用列名,邏輯和數(shù)字運(yùn)算符和常量的任意合法組合組成表達(dá)式。以下是一些例子:
dv.RowFilter = "Country = 'USA'";
dv.RowFilter = "EmployeeID >5 AND Birthdate < #1/31/82#"
dv.RowFilter = "Description LIKE '*product*'"
讓我們來看一下過濾器的基本規(guī)則和運(yùn)算符。
過濾字符串是表達(dá)式的邏輯連接??梢杂肁ND,OR,NOT來連接成一個(gè)較短的表達(dá)式,也可以使用圓括號(hào)來組成子句,指定優(yōu)先的運(yùn)算。
通常包含列名的子句同字母、數(shù)字、日期或另一個(gè)列名進(jìn)行比較。這里,可以使用關(guān)系運(yùn)算符和算術(shù)運(yùn)算符,如>=, <, >, +, *, % (取模)等等。
如果要選取的行并不能方便地通過算術(shù)或邏輯運(yùn)算符表達(dá),你可以使用IN操作符。以下代碼顯示如何選取一個(gè)隨機(jī)行:
dv.RowFilter = "employeeID IN (2,4,5)"
你也可以使用通配符*和%,它們同LIKE運(yùn)算符一起使用時(shí)顯得更有用。它們都表示任意數(shù)量的字符,可以相互替代使用。
請(qǐng)注意,如果在LIKE子句中已經(jīng)有了*或%字符,你必須用方括號(hào)將其括起,以免歧義。如果很不幸,字符串中方括號(hào)本身也存在了,那么它也必須用將本身括起。這樣,匹配語句會(huì)如下所示:
dv.RowFilter = "Description LIKE '[[]*[]]product[[]*[]]"
通配符只允許在過濾字符串的開頭或結(jié)尾處使用,而不能在字符串中間出現(xiàn)。例如,下列語句會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤:
dv.RowFilter = "Description LIKE 'prod*ct"
字符串必須以單引號(hào)括起,而日期型必須以#符號(hào)括起。字符型值可以使用小數(shù)點(diǎn)和科學(xué)計(jì)數(shù)法。
RowFilter也支持聚合函數(shù),如SUM, COUNT, MIN,MAX, and AVG。如果表中沒有數(shù)據(jù)行,那么函數(shù)將返回NULL。
在介紹RowFilter表達(dá)式的最后,讓我們討論三個(gè)很便利的函數(shù):Len,IIF和Substring。
正如其名,Len()返回特定表達(dá)式的長(zhǎng)度。該表達(dá)式可以是一個(gè)列名,也可以是其他合法的表達(dá)式。
Substring()返回指定的表達(dá)式自特定位置開始,特定長(zhǎng)度的字符子串。
我最喜歡用的是IIF(),它按照邏輯表達(dá)式的值有一到兩個(gè)值。IIF是IF-THEN-ELSE語句的緊湊表達(dá)。語法如下:
IIF(expression, if_true, if_false)
通過該函數(shù),可以建立非常復(fù)雜的過濾字符串。例如,假定你從SQL Server的Northwind數(shù)據(jù)庫(kù)中取得Employees表,下列表達(dá)式可以選出那些employeeID小于6且lastname為偶數(shù)個(gè)字符和employeeID大于6且lastname為奇數(shù)個(gè)字符的員工。
IIF(employeeID<6, Len(lastname) %2 =0, Len(lastname) %2 >0)
4.3 DataView 的排序
DataView支持Sort屬性,可以用來對(duì)視圖中的內(nèi)容排序。Sort由用逗號(hào)分隔的列名表達(dá)式進(jìn)行排序。通過在任何列名后加ASC或者DESC限定詞,可以使得字段按照上升或者下降的順序排列。如果沒有方向限定詞,默認(rèn)順序?yàn)锳SC。
DataView是內(nèi)存中的對(duì)象,所以排序在本地進(jìn)行,無需調(diào)用數(shù)據(jù)庫(kù)服務(wù)器。
實(shí)例篇
實(shí)例1.DataTable分組統(tǒng)計(jì)數(shù)據(jù)
Name
Subject
Scores
Jack
001
90
Jack
002
85.5
Tom
001
78.5
Jerry
001
59
Tom
002
100
如上表是dt中的數(shù)據(jù),如果要分組進(jìn)行統(tǒng)計(jì)各學(xué)生的平均科目成績(jī),
可以使用如下的方法(當(dāng)然如果你的.Net版本支持Linq的話,可以使用Linq)
思路:找出所有的學(xué)生,遍歷表,計(jì)算該學(xué)生的平均成績(jī),參考代碼如下:
//獲取所有的學(xué)生
DataView myDataView = new DataView(dt);
string[] strComuns ={ "Name"};
DataTable dtTemp = myDataView.ToTable(true, strComuns);
//新建DataTable存儲(chǔ)結(jié)構(gòu),結(jié)構(gòu)同dt
DataTable dtNew=dt.Clone();
//根據(jù)學(xué)生統(tǒng)計(jì)數(shù)據(jù)
for (int i = 0; i < dtTemp.Rows.Count; i++)
{
DataRow drDetail = dtNew.NewRow();
drDetail["Name"] = dtTemp.Rows[i]["Name"].ToString();
drDetail["Scores"] = dt.Compute("AVer(Scores)", "Name='" + dtTemp.Rows[i]["Name"].ToString() + "'");
dtNew.Rows.Add(drDetail);
}