数据库-ADONET-排序、搜索和筛选

 

排序、搜索和筛选

如何使用一个值或一组值来查找DataTable中的特定行?

如何使用筛选程序是只有满足条件的行可见?

如何控制要访问或者显示的行的排序顺序?

可以使用:

DataRowCollection类的Find方法,DataTable类是Select方法,DataView对象和DataRowView对象。

1           使用DataTable对象的搜索和筛选功能

DataTable对象公开了两个方法,它们可以用来根据搜索标准查找数据。

Find方法,根据主键值来查找数据。

Select方法,类似于筛选程序,根据更灵活的搜索标准返回多行数据。

1.1         根据主键值查找行

查询数据库以获取信息时,通常都会希望,根据其主键列的值,来获取特定行的数据。

可以使用以下查询:

Select CustomerID,CompanyName,ContactName,Phone from Customers where CustomerID=”ALFKI”

还可以根据行的主键值,在DataTable中查找DataRow

尽管Find方法是为DataTable对象设计的,但是,它实际上是由DataRowCollection类公开的。

Find方法接受一个包含要查询的行的主键值作为参数,因为主键值是惟一的,所以Find方法只能返回一行DataRow

Dim strConn, strSql as string

strConn=”Provider=SQLOLEDB;Data Source=(local)"NetSDK; Initial Catalog=Northwind;
Trusted_Connection=Yes;”

strSql=”select CustomerID,CompanyName,ContactName,Phone from Customers”

Dim da as New Oledb.OledbDataAdapter(strSql,strConn)

Dim tbl as new DataTable

Da.fill(tbl)

Tbl.PrimaryKey=new DataColumn(){tbl.Columns(“CustomerID”)}

Dim row as DataRow=tbl.Rows.Find(“ALFKI”)

If row Is Nothing then

     Console.WriteLine(“Row Not Found.”)

Else

     Console.WriteLine(Row(“CompanyName”))

End IF

注意:

从技术角度来说,DataTable可以包含拥有相同主键值的多个行。

如果,将DataSetEnforceConstraints属性设置为假False,那么即使违反了主键约束,DataTable也不会抛出异常。

Find方法将返回找到的所有目标主键值的行。

Find方法,针对DataTable的主键包含多个DataColumn对象的场景,进行了重载。(组合主键)

例如:对于【Order Details】表,主键是OrderID/ProductID,查找演示如下:

Dim strConn,strSql as string

strConn=”...”

strSql=”select OrderID,ProductID,Quantity,UnitPrice from [Order Details]”

dim da as New OleDbDataAdapter(strSql,strConn)

dim tbl as new DataTable()

da.Fill(tbl)

tbl.PrimaryKey=new DataColumn(){tbl.Column(“OrderID”),tbl.Columns(“ProductID”)}

Dim objCriteria as new Object(){10643,28}

Dim row as DataRow=tbl.Rows.Find(objCriteria)

If row Is Nothing Then

     Console.WriteLine(“Row Not Found”)

Else

     Console.WriteLine(“row(“Quantity”) & “ – “ & row(“UnitPrice”))

End If

1.2         执行更动态的搜索

根据主键值查找行,是很高效的。

但是,并非所有搜索都是如此直观。

如果希望查找“位于美国而不在西雅图市的客户”,该怎么办?可以使用Where子句向查询添加一个条件,如下:

Select CustomerID,CompanyName,ContactName,Phone,City,Country from Customers
where Country=”USA” AND City <> “Seattle”

ADONET中,还可以用DataTable对象的Select方法来实现类似的条件查询。

Dim strConn as string=”Provider=SQLOLEDB;Data Source=(local)"NETSDK;Initial Catalog=Northwind;
Trusted_Connection=Yes;”

Dim strSql as String=”select CustomerID,CompanyName,ContactName,Phone,City,Country
from Customers”

Dim da as New OleDbDataAdapter(strSql,strConn)

Dim tbl as new DataTable()

Da.Fill(tbl)

Dim arows as DataRow()

Dim row as DataRow

Arows=tbl.select(“Country=’USA’ AND City <> ‘Seattle”)

For Each row in arows

     Console.WriteLine(row(“CompanyName”) & “ – “ & row(“City”) & “ – “ & row(“Country”))

Next row

1.3         执行通配符搜索

ADONET允许使用通配符进行搜索。

SQL语句中查询CustomerID列是以字母A开始的客户,

Select CustomerID,CompanyName from Customers where CustomerID LIKE ‘A%’

可以在字符串的开始或者结尾使用“%*”作为通配符。

strFilter=”State LIKE ‘New %’” – 将返回在以New开头地区的客户

strFilter=”State LIKE ‘% Dakota ‘” – 将返回北Dakota和南Dakota的客户

ADONET不能使用单字母通配符(如:“?”、“_”等)

1.4         使用分隔符

在搜索条件中,不能简单的使用“单引号”括住一个字符串,就拉倒了。

如果是动态构建搜索条件,其中可能会包含“单引号”,那么搜索条件就必须重复它(就是替换成’’),这可以用String类的Replace方法处理。

strCriteria=”LastName=’” & strLastName.Replace(“ ’ ”, ” ’’ ”) & “’”

以上是对于“字符串”的处理,那么怎么分隔日期?

使用pound号(就是#号)括住日期。

strCriteria=”OrderData>= #01/02/2002# AND OrderDate < #02/02/2002#”

在某些情况下,需要在搜索条件中分隔列名,原因可能是:

列名中有空格或其他非字母字符

列名是保留单词,如LIKESUM等等

ADONET中,可以使用方括号来作为“列分隔符”。

strCriteria=”[Space In Name]=3”

如果在列名中有列分隔符,又怎么办?

可以在条件字符串的结束分隔符“)”之前用转移字符“"”。比如:列名为Bad]Column[Name,可以这样写:strCriteria=”[Bad"]Column[Name]=5”

需要特别注意的是,对于C#来说,由于“"”是转义字符,所以实际的字符串应该这样写:

“[Bad""]Column[Name]=5”

1.5         使用附加Select方法

Select方法有一些重载方法,其中的参数包括:

只提供搜索字符串

包括排序顺序以及控制要搜索的行的状态参数(例如:仅搜索添加的行或仅搜索被修改的行)

1.5.1   包括“排序顺序”

可以通过使用Select重载方法之一,来空值返回的DataRow对象的顺序。

Sql查询中,可以使用ORDER BY子句,来控制有查询返回的数据的排序顺序。

例如:

Select CustomerID,CompanyName,Phone,City from Customers ORDER BY City

如果是City按照降序排序,则改为ORDER BY City DESC

DataTableSelect方法,使用示例如下:

Dim strConn,strSql as String

strConn=”Provider=SQLOLEDB;Data Source=...;Initial Catalog=Northwind;
Trusted_Connection=Yes;”

strSql=”select CustomerID,CompanyName,Phone,City,Country from Customers”

Dim da as New Oledb.OleDBDataAdapter(strSql,strConn)

Dim tbl as New DataTable()

Da.Fill(tbl)

Dim strCriteria As String=”Country=’USA’ AND City <> ‘Seattle’”

Dim strSortOrder as string=”City DESC”

Dim arows as DataRow()=tbl.select(strCriteria,strSortOrder)

Dim row as DataRow

For each row in arows

    Console.WriteLine(row(“CompanyName”) & “ – “ & row(“City”) & “ – “ & row(“Country”))

Next Row

1.5.2   指定要搜索的行的状态RowState

使用Select方法的重载版本之一,指定DataViewRowState枚举值作为参数,可以只对特殊状态的行进行搜索。

举例:希望只检查DataTable中被修改的和被删除的行,使用DataViewRowState枚举类型中的ModifiedOriginalDeleted,将筛选和排序参数使用空串,具体如下:

Dim dvrs as DataViewRowState

Dvrs=DataViewRowState.ModifiedOriginal Or DataViewRowState.Deleted

Dim arows() as DataRow=tbl.Select(“”,””,dvrs)

Dim row as DataRow

For Each row in arows

    Console.WriteLine(row(“CompanyName”,DataRowVersion.Original))

Next Row

这里要注意的是,被删除的行只能检查行的“原始值Original”。

2          DataView对象

DataTableSelect方法,它有两方面的局限性。

第一:因为它接受动态的搜索条件,所以效率不高;

第二:WindowsWEB窗体都不支持“绑定”到Select方法的返回值(DataRow数组)

ADONET针对此问题,提供的解决方案是“DataView”对象。

ADONET体系中DataTable对象基本等价于数据库中的表,所以可以假设DataView对象类似于视图。

2.1         DataView对象从DataTable中返回数据

DataView对象不维护自己的数据副本。

当通过DataView访问数据时,DataView将返回存储在相应DataTable中的数据。

类似的,数据库中的视图也是一样,查询一个视图时,数据库会从视图所引用的一个或多个表中返回数据。

2.2         DataView对象不是SQL查询

数据库的视图实际上就是一个查询。

在数据库中创建视图时,要提供数据库将要执行的,返回视图的数据查询:

CREATE VIEW ViewCustomersAndOrders AS

            SELECT c.CustomerID,c.CompanyName,c.ContactName,c.Phone,o.OrderID,o.EmployeeID,
            o.OrderDate

            FROM Customers c,Orders o WHERE c.CustomerID=o.CustomerID

而,ADONETDataView对象可以,筛选、排序、搜索DataTable的内容,但——它们并非SQL查询。

不能用DataView在两个DataTable间联结Join数据。

不能用DataView查看DataTable中的部分列。

DataView确实支持基于动态标准的行筛选,但是,它们只能访问一个DataTable,而且,DataTable中所有列都可通过DataView得到。

DataRelation来模拟连接

可以用DataRelation配合一个基于表达式的列模拟联结。

比如说:有一个客户DataTable和一个订单DataTable,可以在两个表之间创建关系,然后在订单表中添加基于表达式的列(用来显示客户表的列):

Ds.Relations.Add(“CustomersOrders”,ds.Tables(“Customers”).Columns(“CustomerID”),
ds.Tables(“Orders”).Columns(“CustomerID”))

Ds.Tables(“Orders”).Columns.Add(“CompanyName”,GetType(String),
“Parent(CustomersOrders).CompanyName”)

3          在代码中使用DataView对象

DataView对象提供了与DataTable对象的Select方法类似的功能。

3.1         创建DataView对象

要使用DataView对象查看DataTable中数据,必须【将它与DataTable关联】。

可以——使用DataViewTable属性;或者在DataView构造函数中——指定所要使用的DataTable

Dim tbl as New DataTable(“TableName”)

Dim vue as DataView

Vue=new DataView()

Vue.Table=tbl

Vue=new DataView(tbl)

注意:如果使用DataView属性Table来设置关联的DataTable时,一定要保证DataTableTableName不能是默认值(就是空字符串)。

这个限制在使用DataView的构造函数是就没有。

DataView的另一个构造函数,签名与DataTable.Select方法极为接近。

在其中,需要设置(DataViewTableRowFilterSortRowStateFilter

Dim tbl as New DataTable(“Customers”)

Dim dvrs as DataViewRowState

Dvrs=DataViewRowState.ModifiedOriginal or DataViewRowState.Deleted

Dim vue as newDataView()

Vue.Table=tbl

Vue.RowFilter=”Country=’USA’”

Vue.Sort=”City DESC”

Vue.RowStateFile=dvrs

Vue=new DataView(tbl,”Country=’USA’”,”City DESC”, dvrs)

3.2         使用RowStateFilter属性

RowStateFilter属性接受DataViewRowState枚举类型值。

RowStateFilter属性,能起到双重筛选程序的作用。比如:值ModifiedOriginal,表示修改过的行,会显示原始值。

DataViewRowState枚举值表

说明

Added

包括新添加的行

CurrentRows

包括未删除的行(这是默认值)

Deleted

包括被删除的行。

ModifiedCurrent

包括被修改的行,且显示“当前值”

modifiedOriginal

包括被修改的行,且显示“原始值”

None

不包括任何行

OriginalRows

所有的行(被删除的、被修改的、未被删除的),都显示“原始值”

Unchanged

包括未被修改的行

3.3         使用DataRowView对象

在使用DataTable.Select方法时,存在以下问题:如果指定了ModifiedOriginal,那么返回的是被修改过的行,对于返回的DataRow对象,需要调用过程才能得到行的原始值。

因为DataView对象返回数据使用的是专门的“DataRowView对象”。

DataRowView提供了与DataRow类似的功能,它公开了默认的Item属性,使用该属性,通过提供列名或者列索引来访问列的内容。DataRowViewItem属性,可以用来检查和修改行的内容;但是,“通过DataRowView只能使用一个版本的行数据”,也就是说,在DataView对象的DataRowVersion属性中指定哪个版本的数据,DataRowView就只能显示这个版本数据。

Dim tbl As New DataTable(“Customers”)

...

Dim vue As DataView

Vue=New DataView(tbl)

Dim row as DataRowView=vue(0)

Console.WriteLine(vue(“CompanyName”)

如果发现DataRowView对象的功能不足以满足要求,可以使用DataRowViewRow属性访问相应的DataRow对象。

3.4         通过DataView检查所有可用数据各行

DataView访问数据与直接访问DataTable数据略有不同。

DataTable通过Row属性公开了自己的数据行(你可以用For Each遍历内容);

DataView则没有此种可枚举的集合来公开数据。

DataView对象公开了一个Count属性,该属性返回DataView可见行的数量。通过它可以构造一个For循环检查各行。

DataView还公开了一个返回IEnumerator对象的方法(GetEnumerator)。IEnumerator对象属于System.Collections命名空间,提供了与DataReaderMoveNext方法类似的导航功能。

Dim tbl as New DataTable(“Customers”)

...

Dim vue as DataView

Vue=New DataView(tbl,””,””,DataViewRowState.ModifiedOriginal)

Dim rowView as DataRowView

 

Dim intCounter as Integer

For intCounter=0 to vue.count-1

     RowView=vue(intCounter)

     Console.WriteLine(rowView(“CompanyName”))

Next intcounter

 

Dim objEnum as IEnumerator=vue.GetEnumerator()

Do While objEnum.MoveNext()

     Row=Ctype(objEnum.Current,DataRowView)

     Console.WriteLine(row(“Companyname”))

Loop

3.5         DataView中搜索数据

DataView对象使用:RowFilterRowStateFilter——支持“筛选”。

它还使用:FindFindRows方法——支持“搜索”。

3.5.1   Find方法

使用Find方法,首先要设置DataViewSort属性。Find方法根据Sort属性中指定的列来查找,可以 提供一个或多个值。

不过,DataViewFind方法的返回值:不是DataRow或者DataRowView对象;它返回一个整数值,对应所需行在DataView中的索引。如果没找到,返回值为-1

Dim strConn As String =”Providor=SQLOLEDB;Data Source=...;Initial Catalog=Northwind;
Trusted_Connection=Yes;”

Dim strSql As String=”Select ComstomerID,CompanyName,ContactName,Phone,City,Country
from Customers”

Dim da As New OleDBDataAdapter(strSql,strConn)

Dim tbl As new DataTable()

Da.Fill(tbl,”Customers”)

 

Dim vue as New DataView(tb)

Vue.Sort=“ContactName”

Dim i As Integer=vue.Find(“Fran Wilson”)

If i=-1 Then

    Console.WriteLine(“Row Not Found”)

Else

    Console.WriteLine(vue(i)(“CompanyName”))

End IF

3.5.2   FindRows方法

DataRowCollection对象中,其Find方法会根据DataTable对象的“PrimaryKey属性”,进行搜索,因为(主键也与惟一键约束相关联),所以最多只能有一行满足
DataRowCollection.Find
方法所指定的条件。

然而,DataView对象的Find方法是根据(其Sort属性中指定的列)来进行搜索,DataView中的数据在此排序列可能有多行数据是相同值,此时不能用DataView.Find定位所有的【相同值数据行】,因为Find方法返回值是一个整数。

DataView对象的另一个方法【FindRows】可以完成这种功能,调用方法跟Find一样,但它返回满足条件的DataRowView对象数组。

...

Dim vue As New DataView(tbl)

Vue.Sort=”Country”

Dim arows as DataRowView()=vue.FindRows(“Spain”)

If arows.Length=0 Then

    Console.WriteLine(“没找到”)

Else

    Dim row As DataRowView

    For Each row in arows

           Console.WriteLine(row(“City”))

    Next Row

End If

3.6         修改DataRowView对象

DataRowView对象修改一行数据,类似于修改DataRow的内容。

DataRowView对象也公开了BeginEditEndEditCancelEditDelete方法。

创建新数据行时,DataRowViewDataRow有点不同:

DataView有一个AddNew方法,它返回一个新DataRowView,在返回的DataRowView调用EndEdit方法之后,新行才真正被添加到底层的DataTable

Dim tbl as New DataTable(“Customers”)

...

Dim vue as New DataView(tbl)

Dim row as DataRowView=vue.AddNew()

Row(“CustomerID”)=”ABCDE”

Row(“CompanyName”)=”New Company”

Row(“ContactName”)=”New Contact”

Row(“Phone”)=”(617) 555-1212”)

Row.EndEdit()

修改一行

Row.BeginEdit()

Row(“CompanyName”)=”Modified”

Row.EndEdit()

删除一行

Row.Delete()

 

posted @ 2008-12-01 07:57  怒杀神  阅读(678)  评论(0编辑  收藏  举报