数据库-ADONET-在数据集DataSet中使用关系对象DataRelation处理关系
處理關(guān)系數(shù)據(jù)
數(shù)據(jù)庫(kù)中,表很少是獨(dú)立結(jié)構(gòu)的,大部分?jǐn)?shù)據(jù)庫(kù)都包含相互關(guān)聯(lián)的表。
在構(gòu)建應(yīng)用程序時(shí),會(huì)遇到——顯示或者通過程序設(shè)計(jì)訪問數(shù)據(jù)庫(kù)中相關(guān)表的數(shù)據(jù)的情況。
用戶會(huì)希望,能通過在不同的表之間定位,來(lái)方便的找到相關(guān)的行;當(dāng)父行被修改時(shí),會(huì)希望改動(dòng)可以向下級(jí)聯(lián)到子行上去。
1????????? 關(guān)系數(shù)據(jù)訪問——概述
ADONET不是關(guān)系數(shù)據(jù)訪問的先驅(qū)。
首先回顧一下處理相關(guān)表數(shù)據(jù)的常見方法
1.1???????? 聯(lián)合查詢(Join查詢)
Join查詢要早于所有的Microsoft數(shù)據(jù)訪問技術(shù)。
它是——以單個(gè)查詢獲取多個(gè)表中數(shù)據(jù)的簡(jiǎn)單、標(biāo)準(zhǔn)的方法。
舉例如下:
Select c.CustomerID,c.CompanyName,c.ContactName,c.Phone,o.OrderID,o.EmployeeID,
o.OrderDate,d.ProductID,d.Quantity,d.UnitPrice
from Customers c, Orders o, [Order Details] d
Wherr c.CustomerID=o.CustomerID and o.OrderID=d.OrderID
Join查詢的好處:
l?是被廣泛接受的標(biāo)準(zhǔn)
l?它將結(jié)果返回到一個(gè)單獨(dú)的結(jié)構(gòu)中
l?很容易篩選
Join查詢的缺點(diǎn):
l?會(huì)返回冗余數(shù)據(jù)。假如客戶有100個(gè)訂單,它會(huì)將客戶信息返回到每個(gè)訂單上
l?難于更新。
l?難于同步。
1.2???????? 單獨(dú)查詢
使用單獨(dú)查詢獲取各表中的數(shù)據(jù),并形成單獨(dú)的結(jié)構(gòu)。
好處:
l?比聯(lián)合查詢返回的數(shù)據(jù)總量少
l?更適合更新
l?適合多個(gè)數(shù)據(jù)源
缺點(diǎn):
l?需要同步代碼
l?難于篩選
1.3???????? 層次化的ADO Recordset對(duì)象
ADO 2.0引入了層次化的Recordset的概念。
使用特殊的提供程序和專門的查詢語(yǔ)法將多個(gè)查詢的結(jié)果組合到一個(gè)結(jié)構(gòu)中。
示例:將獲取的Customers、 Orders、 Order Details表中的內(nèi)容存放到一個(gè)層次化Recordset中。
Dim rsCustomers as ADODB.Recordset, rsOrders As ADODB.Recorders
Dim rsOrderDetails As ADODB.Recordset
Dim strConn As String, strSQL as String
strConn=”Provider=MSDataShape;Data Provider=SQLOLEDB; Data Source={local}"NetSDK; Initial Catalog=Northwind; Trusted_Connection=Yes;”
strSql=”SHAPE {select CustomerID,CompanyName,ContactName,ContactTitle from Customers} AS
?Customers APPEND ({SHAPE {select OrderID,CustomerID,EmployeeID,OrderDate from Orders } AS Orders APPEND ({select OrderID,ProductID,UnitPrice,Quantity from [Order Details]} AS OrderDetails RELATE ‘OrderID’ TO ‘OrderID’) AS OrderDetails) AS Orders RELATE ‘CustomerID’ TO ‘CustomerID’ ) AS Orders”
Set rsCustomers=New ADODB.Recordset
rsCustomers.Open strSQL,strConn,adOpenStatic,adLockBatchOptimistic
Set rsOrders=rsCustomers.Fields(“Orders”).Value
Set rsOrderDetails=rsOrders.Fields(“OrderDetails”).Value
這里有3個(gè)Recordset對(duì)象,它們都引用了一個(gè)結(jié)構(gòu)中的數(shù)據(jù)。對(duì)最高級(jí)別的Recordset進(jìn)行定位時(shí),子Recordset對(duì)象中只有相關(guān)的數(shù)據(jù)才是可見的。
l?優(yōu)點(diǎn):
1.??????? 比Join查詢返回的數(shù)據(jù)總量小
2.??????? 返回的數(shù)據(jù)在一個(gè)單獨(dú)的結(jié)構(gòu)中
3.??????? 不需要復(fù)雜的同步代碼
4.??????? 適合簡(jiǎn)單的更新
l?缺點(diǎn):
1.??????? 查詢語(yǔ)句難于使用(SHAPE語(yǔ)法)
2.??????? 提供的控制能力有限
3.??????? 只能查詢單獨(dú)的數(shù)據(jù)源
4.??????? 難于篩選
1.4???????? ADONET的DataRelation對(duì)象
DataRelation對(duì)象不需要額外的提供程序,而且不需要難于使用的SHAPE查詢。
DataRelation對(duì)象屬于DataSet對(duì)象架構(gòu)的一部分。
DataRelation結(jié)合了——單獨(dú)查詢和層次化的Recordset方法的最好功能——以管理來(lái)自相關(guān)表的數(shù)據(jù),并幾乎克服了它們的所有缺點(diǎn)。
l?好處:
1.??????? 比Join查詢返回的數(shù)據(jù)少
2.??????? 簡(jiǎn)化了相關(guān)數(shù)據(jù)的定位
3.??????? 不需要復(fù)雜的同步代碼
4.??????? 可以處理復(fù)雜的更新(例如:在提交新訂單之前提交新的客戶,同時(shí)還可以在刪除現(xiàn)有客戶之前先刪除現(xiàn)有訂單。而且,如果有一系列未提交的訂單和訂單細(xì)節(jié),可以在提交新訂單細(xì)節(jié)之前,提取服務(wù)器為新訂單所產(chǎn)生的自動(dòng)遞增值。)
5.??????? 它們是動(dòng)態(tài)的(在查詢相關(guān)數(shù)據(jù)庫(kù)表之前或之后,通過程序設(shè)計(jì)來(lái)創(chuàng)建、修改和刪除DataRelation對(duì)象)
6.??????? 支持層疊改變(可以通過用與DataRelation相關(guān)聯(lián)的ForeignkeyConstraint屬性來(lái)空值是否對(duì)——一行所做的改動(dòng)層疊到子行上去。)
7.??????? 支持從不同的數(shù)據(jù)源創(chuàng)建層次結(jié)構(gòu)
l?缺點(diǎn)
1.??????? 難于篩選(DataRelation對(duì)象不是只提取這種子行)
2????????? 在代碼中使用DataRelation對(duì)象
盡管可以純粹的編寫代碼來(lái)對(duì)多個(gè)表中的數(shù)據(jù)進(jìn)行(定位、驗(yàn)證、匯總、級(jí)聯(lián)更改),但是使用ADONET的DataRelation對(duì)象,可以迅速和簡(jiǎn)單的實(shí)現(xiàn)這些功能。
2.1???????? 創(chuàng)建DataRelation對(duì)象
DataRelation對(duì)象有幾個(gè)重要的屬性,你可以在構(gòu)造函數(shù)中設(shè)置它們。
l?提供一個(gè)名稱,以便在集合中定位對(duì)象
l?指定基于該關(guān)系的父列和子列
n?可以接受單個(gè)的DataColumn對(duì)象
n?也可以接受DataColumn數(shù)組
l?代碼示例
??????? Dim rel As DataRelation
??????? rel = New DataRelation("訂單關(guān)系", DataSet1.Tables("訂單").Columns("訂單ID"), DataSet1.Tables("訂單明細(xì)").Columns("訂單ID"))
??????? DataSet1.Relations.Add(rel)
如果希望定義基于多列的關(guān)系,那么可以使用接受DataColumn對(duì)象數(shù)組的構(gòu)造函數(shù)。
DataRelation的兩個(gè)特別構(gòu)造函數(shù),公開了第四個(gè)參數(shù)(用來(lái)知名是否創(chuàng)建約束——以增強(qiáng)基于新關(guān)系的引用完整性)。默認(rèn)時(shí),創(chuàng)建新DataRelation對(duì)象,如果沒有約束,會(huì)向DataTable中添加約束。
創(chuàng)建的新DataRelation對(duì)象,應(yīng)該添加到DataSet對(duì)象的Relations集合。
2.2???????? 查找關(guān)系數(shù)據(jù)
DataRelation對(duì)象的主要用途就是,在不同的DataTable對(duì)象中查找關(guān)系數(shù)據(jù)。
但是,DataRelation不處理這個(gè)任務(wù),或者說不直接處理。
這個(gè)功能實(shí)際上是通過DataRow對(duì)象的GetChileRows、GetParentRow、GetParentRows方法提供的。
在調(diào)用以上DataRow對(duì)象方法時(shí),要指定一個(gè)DataRelation參數(shù)
2.2.1?? DataRow對(duì)象的GetChildRows方法
該方法用于查找一個(gè)與另一個(gè)DataTable的子行相關(guān)聯(lián)的行。
使用該方法,需要調(diào)用DataRow對(duì)象的GetChildRows,并提供定義了DataTable對(duì)象之間關(guān)系的DataRelation對(duì)象的名稱(或者直接提供對(duì)象)
該方法的返回值,返回關(guān)系型數(shù)據(jù)(DataRow對(duì)象的一個(gè)數(shù)組)
2.2.2?? DataRow對(duì)象的GetParentRow方法
DataRelation對(duì)象,不僅可以在層次結(jié)構(gòu)中由上至下搜索,還可以由下至上。
DataRow對(duì)象的GetParentRow方法,根據(jù)DataSet對(duì)象中的DataRelation對(duì)象來(lái)查找父行。
該方法,需要DataRelation對(duì)象作參數(shù),或者是,包含DataRelation對(duì)象名字的字符串。
2.2.3?? DataRow對(duì)象的GetParentRows方法(注意,有個(gè)復(fù)數(shù)s)
如果處理的是一種多對(duì)多的關(guān)系,并且希望檢查特定DataRow的所有父行,那么就可以使用DataRow對(duì)象的GetParentRows方法了。
此方法與上面的方法簽名式相同
2.2.4?? 選擇要查看的數(shù)據(jù)版本
假設(shè):已經(jīng)構(gòu)建了一個(gè)讓用戶從數(shù)據(jù)庫(kù)中返回?cái)?shù)據(jù)并修改該數(shù)據(jù)的應(yīng)用程序。
但是使用這個(gè)應(yīng)用程序的員工并不是非常可靠的。他們會(huì)犯錯(cuò)誤。
所以應(yīng)用程序使用看一些DataSet公開的功能,將所做的改動(dòng)存儲(chǔ)到一個(gè)文件中,而不是提交給數(shù)據(jù)庫(kù)。
因此,必須創(chuàng)建第二個(gè)應(yīng)用程序,以便讓管理員檢查員工使用程序#1輸入的掛起更改,這個(gè)審核程序能同時(shí)顯示DataSet中修改行的原始值和修改后的值。
?
我們可以用DataRow對(duì)象的Item屬性檢查行中特定列的原始值和當(dāng)前值。
另外,DataRow對(duì)象的GetChildRows、GetParentRow、GetParentRows方法,可以使用DataRowVersion類型枚舉值作參數(shù),來(lái)指明訪問哪個(gè)版本的數(shù)據(jù)。
2.3???????? 使用DataRelation對(duì)象驗(yàn)證數(shù)據(jù)
DataRelation對(duì)象的一個(gè)主要功能就是——驗(yàn)證數(shù)據(jù)(另一個(gè)主要功能是:對(duì)來(lái)自相關(guān)DataTable的數(shù)據(jù)進(jìn)行定位)
在定義兩個(gè)DataTable之間的關(guān)系的時(shí)候,一般都會(huì)希望保證在子DataTable中不會(huì)出現(xiàn)“孤立”的數(shù)據(jù),也就是說,希望能夠防止用戶在Orders表中輸入在Customers表中沒有對(duì)應(yīng)行的那些行。
可以用DataRelation對(duì)象來(lái)增強(qiáng)對(duì)相關(guān)DataTable對(duì)象的約束。
2.3.1?? 創(chuàng)建約束
在默認(rèn)情況下,創(chuàng)建DataRelation對(duì)象時(shí)能夠確保在父級(jí)DataTable對(duì)象上有一個(gè)惟一約束,在子DataTable上有一個(gè)外鍵約束。
l?代碼演示:(在Customers的DataTable對(duì)象的CustomerID列上創(chuàng)建一個(gè)惟一約束,在Orders的DataTable上CustomerID列上創(chuàng)建一個(gè)外鍵約束)
??????? Dim daCustomers As New OleDb.OleDbDataAdapter("select 客戶ID,公司名稱,聯(lián)系人姓名from 客戶", OleDbConnection1)
??????? Dim daOrders As New OleDb.OleDbDataAdapter("select 訂單ID,客戶ID,訂購(gòu)日期from 訂單", OleDbConnection1)
?
??????? Dim ds As New DataSet
??????? daCustomers.Fill(ds, "客戶")
??????? daOrders.Fill(ds, "訂單")
?
??????? ds.Relations.Add("CustomersOrders", ds.Tables("客戶").Columns("客戶ID"), ds.Tables("訂單").Columns("客戶ID"))
?
?
??????? ListBox1.Items.Add("父表——客戶表,現(xiàn)在有" & ds.Tables("客戶").Constraints.Count & "個(gè)約束;它叫做:" & ds.Tables("客戶").Constraints(0).ConstraintName)
??????? ListBox1.Items.Add("子表——訂單表,現(xiàn)在有" & ds.Tables("訂單").Constraints.Count & "個(gè)約束;它叫做:" & ds.Tables("客戶").Constraints(0).ConstraintName)
?
2.3.2?? 使用現(xiàn)有約束
還可以事先定義出自己的約束。
新的DataRelation將使用現(xiàn)有的約束而不是創(chuàng)建新的約束。
??????? '首先給客戶表定義主鍵
??????? With ds.tables("客戶")
??????????? .PrimaryKey = New DataColumn() {.Columns("客戶ID")}
??????? End With
??????? '然后給訂單表定義外鍵
??????? With ds.Tables("訂單")
??????????? '.Constraints.Add("FK_CustomersOrders", ds.Tables("客戶").Columns("客戶ID"), .Columns("客戶ID"))
??????????? .Constraints.Add(New ForeignKeyConstraint("kd", ds.Tables("客戶").Columns("客戶ID"), .Columns("客戶ID")))
??????? End With
??????? '現(xiàn)在添加關(guān)系
??????? ds.Relations.Add("co", ds.Tables("客戶").Columns("客戶ID"), ds.Tables("訂單").Columns("客戶ID"))
?
??????? '現(xiàn)在顯示
??????? ListBox1.Items.Add("父表- " & ds.Tables("客戶").TableName & "現(xiàn)在有" & ds.Tables("客戶").Constraints.Count & "個(gè)約束")
2?外鍵約束和空值
此處可能引起你懷疑的是——為什么即使在定義了外鍵約束的情況下,還是可能在數(shù)據(jù)庫(kù)和DataSet中出現(xiàn)“孤立”的數(shù)據(jù)?????
難道你不相信可以對(duì)Northwind數(shù)據(jù)庫(kù)運(yùn)行下面的查詢?
Update Orders SET CustomerID=NULL where CustomerID=”ALFKI”
這個(gè)查詢會(huì)成功執(zhí)行,這樣,Orders表中就會(huì)出現(xiàn)不屬于Customers表的客戶訂單了。
要把行設(shè)置為Customers表的恰當(dāng)客戶,你可以:
Update Orders SET CustomerID=’ALFKI’ where CustomerID is NULL
為了證明在Orders表中有外鍵約束,可以運(yùn)行下面的查詢
Update Orders SET customerID=’ZZZZZ’ where CustomerID=’ANTON’
如果Customers表中沒有CustomerID=’ZZZZZ’的行,查詢會(huì)失敗。
在定義數(shù)據(jù)庫(kù)和DataSet時(shí)要記住:在外鍵約束中至少有一列包含NULL值的行,是不受約束限制的。
2.3.3?? 看,約束沒了!
已知,在創(chuàng)建DataRelation時(shí),ADONET默認(rèn)會(huì)保證給DataSet包含——(其簽名與新DataRelation一致的)惟一鍵UniqueConstraint和外鍵ForeignKeyConstraint。
而且,如果DataSet中歐冠呢已經(jīng)有這種約束,新的DataRelation會(huì)自動(dòng)引用它們。
否則,ADONET將會(huì)隱式地創(chuàng)建新的約束。
不過,你也可以指定ADONET不為DataRelation創(chuàng)建約束。當(dāng)你希望使用DataRelation,但不想在DataSet中有相應(yīng)約束時(shí),你可以在DataRelation類的某些構(gòu)造函數(shù)中指定參數(shù)(布爾型參數(shù)createConstraints)。
2.4???????? 自引用DataRelationShip對(duì)象
有時(shí)關(guān)系中的父表和子表是同一個(gè)表。
比如:對(duì)于Northwind數(shù)據(jù)庫(kù)中的Employees表。這個(gè)表中有一個(gè)包含員工ID的列,和一個(gè)包含員工管理者ID的列(ReportsTo)。員工表還有一個(gè)在ReportsTo列上定義的外鍵約束用來(lái)確保它只能接受來(lái)自EmployeeID列的值。
??????? '首先取員工表
??????? Dim da As New OleDb.OleDbDataAdapter("select 雇員ID,姓氏+名字as 姓名, 上級(jí)from 雇員", OleDbConnection1)
??????? da.Fill(ds, "雇員")
?
??????? '給雇員表添加自引用
??????? Dim tbl As DataTable = ds.Tables("雇員")
??????? 'ds.Relations.Add("SelfReferentcing", tbl.Columns("雇員ID"), tbl.Columns("上級(jí)"), False)
??????? ds.Relations.Add(New DataRelation("selfr", tbl.Columns("雇員ID"), tbl.Columns("上級(jí)"), False))
2.5???????? 多對(duì)多關(guān)系
大部分?jǐn)?shù)據(jù)庫(kù)——關(guān)系都是一對(duì)多的。
但是,多對(duì)多的關(guān)系確實(shí)存在。比如:SQL Server中的pubs數(shù)據(jù)庫(kù),其中的authors和titles表,這兩個(gè)表中的數(shù)據(jù)關(guān)系可以認(rèn)為是多對(duì)多的,因?yàn)橐粋€(gè)作者可以寫很多書,而一部書可以有多位作者。然而,由于“外鍵約束需要一個(gè)惟一鍵”,所以這兩個(gè)表并不是直接通過外鍵約束相關(guān)聯(lián)的。這樣可以防止子行在相關(guān)表中有多個(gè)父行。既是意味著沒有直接的多對(duì)多關(guān)系。
Pubs數(shù)據(jù)庫(kù)包括的另外一個(gè)名叫titleauthor的表,這個(gè)表用來(lái)創(chuàng)建非直接多對(duì)多關(guān)系的表。它有一個(gè)復(fù)合主鍵,這個(gè)復(fù)合主鍵有au_id和title_id組成,分別對(duì)應(yīng)authors和titles表的主鍵。
假設(shè)一個(gè)作品有兩位作者,titleauthors表就會(huì)包括該作品的兩個(gè)作者行。
因此,可以用titleauthors表找到特定作品的所有合著作者;或者利用這個(gè)表,找到特定作者寫過的或合寫的所有作品的主鍵值。
下面的代碼演示:從這三個(gè)表中獲取數(shù)據(jù)。在作者表和關(guān)系表、作品表和關(guān)系表——之間添加關(guān)系DataRelation對(duì)象,然后根據(jù)關(guān)系,循環(huán)查找作者表中的行,顯示每一位作者(對(duì)于每個(gè)作者,取關(guān)系表中的子行,每個(gè)子行再反向從作品表中取父行,從而得到每個(gè)作者的作品列表)
??????? Dim da As SqlClient.SqlDataAdapter
??????? '先取作者表數(shù)據(jù)
??????? da = New SqlClient.SqlDataAdapter("select au_id, au_lname + au_fname as name from authors", SqlConnection1)
??????? da.Fill(DataSet1, "作者")
??????? '取作品表數(shù)據(jù)
??????? da.SelectCommand = New SqlClient.SqlCommand("select title_id,title from titles", SqlConnection1)
??????? da.Fill(DataSet1, "作品")
??????? ' 取兩者的關(guān)系表
??????? da.SelectCommand = New SqlClient.SqlCommand("select au_id,title_id from titleauthor", SqlConnection1)
??????? da.Fill(DataSet1, "關(guān)系")
?
??????? '先定義作者表au_id的關(guān)系
??????? DataSet1.Relations.Add("authors_titleauthors", DataSet1.Tables("作者").Columns("au_id"), DataSet1.Tables("關(guān)系").Columns("au_id"), False)
??????? '在定義作品表的title_id的關(guān)系
??????? DataSet1.Relations.Add("titles_titleauthors", DataSet1.Tables("作品").Columns("title_id"), DataSet1.Tables("關(guān)系").Columns("title_id"), False)
?
??????? '下面代碼,用來(lái)顯示效果
??????? Dim row_author, row_title, row_titleauthors As DataRow
??????? For Each row_author In DataSet1.Tables("作者").Rows
??????????? ListBox1.Items.Add(row_author("name"))
??????????? For Each row_titleauthors In row_author.GetChildRows("authors_titleauthors")
??????????????? row_title = row_titleauthors.GetParentRow("titles_titleauthors")
??????????????? ListBox1.Items.Add(vbTab & "《" & row_title("title") & "》")
??????????? Next
?
??????? Next
2.6???????? 在基于表達(dá)式的數(shù)據(jù)列DataColumns對(duì)象中使用關(guān)系對(duì)象DataRelation
你可以用DataColumn對(duì)象的Expression屬性,創(chuàng)建并顯示表達(dá)式;
還可以將基于表達(dá)式的DataColumn對(duì)象與DataRelation對(duì)象結(jié)合,用來(lái)計(jì)算匯總的信息。(例如:子行數(shù)和子數(shù)據(jù)的總和與平均值)
l?代碼演示?
??????? '首先在數(shù)據(jù)集里面收集訂單和訂單明細(xì)表的數(shù)據(jù)
??????? Dim da As New OleDb.OleDbDataAdapter("select * from 訂單", dc)
??????? da.Fill(ds, "訂單")
??????? da.SelectCommand = New OleDb.OleDbCommand("select * from?訂單明細(xì)", dc)
??????? da.Fill(ds, "訂單明細(xì)")
?
??????? '增加兩表中訂單ID的關(guān)系
??????? Dim tblOrders, tblOrderDetails As DataTable
??????? tblOrderDetails = ds.Tables("訂單明細(xì)")
??????? tblOrders = ds.Tables("訂單")
??????? ds.Relations.Add("訂單標(biāo)識(shí)關(guān)系", tblOrders.Columns("訂單ID"), tblOrderDetails.Columns("訂單ID"))
?
??????? '現(xiàn)在添加單項(xiàng)總價(jià)數(shù)據(jù)列-放在明細(xì)表
??????? tblOrderDetails.Columns.Add("單項(xiàng)總價(jià)", GetType(Decimal), "單價(jià)* 數(shù)量* (1- 折扣)")
??????? ' 在訂單表添加數(shù)據(jù)列-用來(lái)保存子行數(shù)
??????? tblOrders.Columns.Add("子行數(shù)", GetType(Integer), "Count(Child.產(chǎn)品ID)")
??????? '在訂單表添加此單總價(jià)列
??????? tblOrders.Columns.Add("此單總價(jià)", GetType(Decimal), "Sum(Child.單項(xiàng)總價(jià)) + 運(yùn)貨費(fèi)")
程序說明:首先,創(chuàng)建起訂單表和訂單明細(xì)表直接的關(guān)系,然后將單項(xiàng)總價(jià)列添加到訂單明細(xì)表,將子行數(shù)和此單總價(jià)列添加到訂單表。
返回子行數(shù)量,要設(shè)置數(shù)據(jù)列對(duì)象的Expression屬性為:Count(Child.產(chǎn)品ID)
注意這種語(yǔ)法適合數(shù)據(jù)表只有一個(gè)相關(guān)子表對(duì)象的情況;如果父表有多個(gè)相關(guān)的子表,需要的語(yǔ)法是:Count(Child(RelationName).產(chǎn)品ID)
最好,在訂單表中添加列,用來(lái)計(jì)算總價(jià):Sum(Child.單項(xiàng)總價(jià))
?
DataColumn.Expression屬性——引用
用來(lái)計(jì)算列的值,或創(chuàng)建聚合列的表達(dá)式。表達(dá)式的返回類型由列的 DataType 來(lái)確定。
Expression 屬性的一個(gè)用途是創(chuàng)建計(jì)算出的列。例如,若要計(jì)算稅值,就要將單價(jià)乘以特定地區(qū)的稅率。由于各地稅率不同,不可能將單一稅率放在一個(gè)列中;于是便用 Expression 屬性來(lái)計(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ù)。這便是您將用來(lái)計(jì)算特定銷售人員所完成的交易數(shù)的方法
表達(dá)式語(yǔ)法
在創(chuàng)建表達(dá)式時(shí),使用 ColumnName 屬性來(lái)引用列。例如,如果一個(gè)列的 ColumnName 是“UnitPrice”,而另一個(gè)是“Quantity”,則表達(dá)式將是:
"UnitPrice * Quantity"
| 注意 |
| 如果在表達(dá)式中使用了某個(gè)列,則該表達(dá)式就存在一個(gè)對(duì)該列的依賴項(xiàng)。重命名或移除依賴列時(shí)不會(huì)引發(fā)異常。當(dāng)訪問缺少了依賴項(xiàng)的表達(dá)式列時(shí),將引發(fā)異常。 |
在為篩選器創(chuàng)建表達(dá)式時(shí),用單引號(hào)將字符串括起來(lái):
"LastName = 'Jones'"
下面的字符是特殊字符,如下面所解釋的,如果它們用于列名稱中,就必須進(jìn)行轉(zhuǎn)義:
"n (newline)
"t (tab)
"r (carriage return)
~
(
)
#
"
/
=
>
<
+
-
*
%
&
|
^
'
"
[
]
如果列名稱包含上面的字符之一,該名稱必須用中括號(hào)括起來(lái)。例如,若要在表達(dá)式中使用名為“Column#”的列,應(yīng)寫成“[Column#]”:
Total * [Column#]
由于中括號(hào)是特殊字符,如果它是列名稱的組成部分,必須使用斜杠 (""") 將中括號(hào)轉(zhuǎn)義。例如,名為“Column[]”的列應(yīng)寫成:
Total * [Column["]]
(只有第二個(gè)中括號(hào)必須轉(zhuǎn)義。)
用戶定義的值
用戶定義的值可以用在將與列值進(jìn)行比較的表達(dá)式內(nèi)。字符串的值應(yīng)括在單引號(hào)內(nèi)。日期值應(yīng)放在磅符號(hào) (#) 內(nèi)。對(duì)于數(shù)值,允許使用小數(shù)和科學(xué)記數(shù)法。例如:
"FirstName = 'John'"
"Price <= 50.00"
"Birthdate < #1/31/82#"
對(duì)于包含枚舉值的列,將值強(qiáng)制轉(zhuǎn)換為整數(shù)數(shù)據(jù)類型。例如:
"EnumColumn = 5"
運(yùn)算符
使用布爾值 AND、OR 和 NOT 運(yùn)算符時(shí)允許串聯(lián)。可以使用括號(hào)來(lái)組合子句和強(qiáng)制優(yōu)先級(jí)。AND 運(yùn)算符優(yōu)先于其他運(yùn)算符。例如:
(LastName = 'Smith' OR LastName = 'Jones') AND FirstName = 'John'
在創(chuàng)建比較表達(dá)式時(shí),允許使用下列運(yùn)算符:
<
>
<=
>=
<>
=
IN
LIKE
在表達(dá)式中還支持下列算術(shù)運(yùn)算符:
+(加)
-(減)
*(乘)
/(除)
%(模數(shù))
字符串運(yùn)算符
若要連接字符串,請(qǐng)使用 + 字符。DataSet 類的 CaseSensitive 屬性的值確定字符串比較是否區(qū)分大小寫。但是,可以用 DataTable 類的 CaseSensitive 屬性重寫該值。
通配符
在 LIKE 比較中,* 和 % 兩者可以互換地作為通配符。如果 LIKE 子句中的字符串包含 * 或 %,那么這些字符應(yīng)用中括號(hào)([])對(duì)其進(jìn)行轉(zhuǎn)義。如果子句中有中括號(hào),那么中括號(hào)字符應(yīng)用中括號(hào)對(duì)其進(jìn)行轉(zhuǎn)義(例如 [[] 或 []])。在模式的開頭和結(jié)尾,或者在模式的結(jié)尾,或在模式的開頭,都允許使用通配符。例如:
"ItemName LIKE '*product*'"
"ItemName LIKE '*product'"
"ItemName LIKE 'product*'"
在字符串的中間不允許使用通配符。例如,不允許 'te*xt'。
父/子關(guān)系引用
通過在列名稱前面加 Parent,就可以在表達(dá)式中引用父表。例如,Parent.Price 引用父表的名為 Price 的列。
通過在列名稱前面加一個(gè) Child,就可以在表達(dá)式中引用子表中的列。但是,因?yàn)樽雨P(guān)系可以返回多行,所以必須在聚合函數(shù)中包括對(duì)子列的引用。例如,Sum(Child.Price) 將返回子表中名為 Price 的列的總和。
如果某個(gè)表有多個(gè)子表,則語(yǔ)法是:Child(RelationName)。例如,如果某個(gè)表有兩個(gè)子表,它們的名稱分別為 Customers 和 Orders,并且 DataRelation 對(duì)象被命名為 Customers2Orders,則引用將為:
Avg(Child(Customers2Orders).Quantity)
聚合
支持下列聚合類型:
Sum(求和)
Avg(平均)
Min(最小值)
Max(最大值)
Count(計(jì)數(shù))
StDev(統(tǒng)計(jì)標(biāo)準(zhǔn)偏差)
Var(統(tǒng)計(jì)方差)。
聚合通常沿著關(guān)系執(zhí)行。通過使用上面列出的函數(shù)之一和上面“父/子關(guān)系引用”中詳述的子表列,來(lái)創(chuàng)建聚合表達(dá)式。例如:
Avg(Child.Price)
Avg(Child(Orders2Details).Price)
聚合也可以在單個(gè)表上執(zhí)行。例如,若要為名為“Price”的列中的數(shù)字創(chuàng)建匯總,就用:
Sum(Price)
| 注意 |
| 如果使用一個(gè)表來(lái)創(chuàng)建聚合,將沒有組合功能。相反,所有行都在列中顯示相同的值。 |
如果表沒有行,聚合函數(shù)將返回空引用(在 Visual Basic 中為 Nothing)。
數(shù)據(jù)類型總是可以通過檢查列的 DataType 屬性來(lái)確定。還可以使用 Convert 函數(shù)來(lái)轉(zhuǎn)換數(shù)據(jù)類型,如下面這一部分所示。
FUNCTIONS
還支持下列函數(shù):
CONVERT
| 說明 | 將特定表達(dá)式轉(zhuǎn)換為指定的 .NET Framework 類型。 |
| 語(yǔ)法 | Convert(expression, type) |
| 參數(shù) | expression — 要轉(zhuǎn)換的表達(dá)式。 type — 值將轉(zhuǎn)換成的 .NET Framework 類型。 |
例如:myDataColumn.Expression="Convert(total, 'System.Int32')"
所有轉(zhuǎn)換都是有效的,只有下列情況例外:Boolean 只能與 Byte、SByte、Int16、Int32、Int64、UInt16、UInt32、UInt64、String 和它本身相互轉(zhuǎn)換。Char 只能與 Int32、UInt32、String 和它本身相互轉(zhuǎn)換。DateTime 只能與 String 和它本身相互轉(zhuǎn)換。TimeSpan 只能與 String 和它本身相互轉(zhuǎn)換。
LEN
| 說明 | 獲取字符串的長(zhǎng)度 |
| 語(yǔ)法 | LEN(expression) |
| 參數(shù) | expression — 要計(jì)算的字符串。 |
例如:myDataColumn.Expression="Len(ItemName)"
ISNULL
| 說明 | 檢查表達(dá)式并返回已檢查的表達(dá)式或返回替換值。 |
| 語(yǔ)法 | ISNULL(expression, replacementvalue) |
| 參數(shù) | expression — 要檢查的表達(dá)式。 replacementvalue — 如果表達(dá)式為 空引用(在 Visual Basic 中為 Nothing),則返回 replacementvalue。 |
例如:myDataColumn.Expression="IsNull(price, -1)"
IIF
| 說明 | 根據(jù)邏輯表達(dá)式的結(jié)果,獲取兩個(gè)值之一。 |
| 語(yǔ)法 | IIF(expr, truepart, falsepart) |
| 參數(shù) | expr — 要計(jì)算的表達(dá)式。 truepart — 表達(dá)式為真時(shí)返回的值。 falsepart — 表達(dá)式為假時(shí)返回的值。 |
例如:myDataColumn.Expression = "IIF(total>1000, 'expensive', 'dear')
TRIM
| 說明 | 移除所有前導(dǎo)的和后綴的空格字符,如 "r、"n、"t、' ' |
| 語(yǔ)法 | TRIM(expression) |
| 參數(shù) | expression — 要剪裁的表達(dá)式。 |
SUBSTRING
| 說明 | 獲取從字符串中的指定點(diǎn)開始,具有指定長(zhǎng)度的子字符串。 |
| 語(yǔ)法 | SUBSTRING(expression, start, length) |
| 參數(shù) | expression — 子字符串的源字符串。 start — 指定子字符串開始位置的整數(shù)。 length — 指定子字符串長(zhǎng)度的整數(shù)。 |
例如:myDataColumn.Expression = "SUBSTRING(phone, 7, 8)"
| 注意 |
| 可以向 Expression 屬性分配一個(gè)空值或空字符串,來(lái)重置該屬性。如果為表達(dá)式列設(shè)置了一個(gè)默認(rèn)值,則在重置 Expression 屬性之后,這個(gè)默認(rèn)值就賦給所有以前填充過的行。 |
?
可以在關(guān)系中使用基于表達(dá)式的DataColumn對(duì)象,從父表對(duì)象中收集數(shù)據(jù)。
可以通過給titleauthor表對(duì)象添加基于表達(dá)式的數(shù)據(jù)列來(lái)簡(jiǎn)化這段代碼,具體的說就是,titleauthor表通過title表使用DataRelation,來(lái)返回title表DataColumn的值。給titleauthor表添加這一列之后,就不需要通過使用GetParentRow方法在title表中查找所需的行。
2.7???????? 層疊更改
有時(shí)候,對(duì)一行所做的更改在相關(guān)的數(shù)據(jù)上會(huì)有影響,或者是(應(yīng)該會(huì)有影響)。例如:刪除一個(gè)訂單,可能也想刪除與這個(gè)訂單關(guān)聯(lián)的明細(xì)行。
不同的數(shù)據(jù)庫(kù)系統(tǒng),處理此種情形的方式,是不同的。
SQL SERVER中,Northwind數(shù)據(jù)列的Order Details表,使用了【外鍵約束】來(lái)防止,用戶從Orders表刪除行的情況。
SQL Server 2000引入“支持是喲個(gè)外鍵約束的層疊改變”。通過定義外鍵約束,使得用戶的更新或者刪除,會(huì)自動(dòng)層疊到相關(guān)表的行上。
ADONET的ForeignKeyConstaint對(duì)象具有類似的特性,它公開了DeleteRule和UpdateRule屬性,設(shè)置這些屬性能控制,在修改外鍵約束的父表數(shù)據(jù)是,會(huì)出現(xiàn)什么情形。
ü?ForeignKeyConstaint對(duì)象的DeleteRule和UpdateRule屬性
DeleteRule和UpdateRule屬性接受System.Data命名空間中的Rule枚舉值。
在默認(rèn)情況下,這兩個(gè)屬性值為Cascade,表示在刪除表中的行時(shí),相關(guān)子行也會(huì)被刪除;而,如果是更新父行列值,子表對(duì)象中相關(guān)行也會(huì)更新。
這兩個(gè)屬性的可選值還有:None、SetDefault、SetNull。
若設(shè)置DeleteRule屬性=None,可以防止刪除子表對(duì)象中受影響的數(shù)據(jù)。
若希望父行更新時(shí)使子表中被約束的行為值為Null,就需要設(shè)置DeleteRule屬性=SetNull
若將屬性設(shè)置為SetDefault,則是使被約束列Default屬性被重置。
2.8???????? Join查詢
很多人依靠Join查詢,從多個(gè)表獲取數(shù)據(jù),返回的結(jié)果可以用DataTable來(lái)存儲(chǔ);
但是,一般不會(huì)建議這樣做。
因?yàn)?#xff0c;一般情況下,DataAdapter能夠檢查存儲(chǔ)在單個(gè)DataTable中的更改,并提交給數(shù)據(jù)庫(kù)指定表。
那么,如何處理Join查詢呢?
簡(jiǎn)單的做法是,將它們分成從單獨(dú)表中返回?cái)?shù)據(jù)的查詢。但是做起來(lái)不是很容易。
?
?
總結(jié)
以上是生活随笔為你收集整理的数据库-ADONET-在数据集DataSet中使用关系对象DataRelation处理关系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广域线路打环测试步骤
- 下一篇: 在虚拟机中安装LINUX