分享
 
 
 

用ADO.NET处理层次数据

王朝c#·作者佚名  2008-06-01
窄屏简体版  字體: |||超大  

ADO.NET 为数据在内存中的操作和储存提供了一种新模式。因此,我们在处理层次数据时该换换脑了。本文将对其独到之处作一个简单的描述。

读者要求:基本把握 Visual C#.NET 、DataAdapter 和 DataSet 。

环境

[配置一]

操作系统: windows 2000 服务器

计算机: Dell Inspiron 8000 笔记本

內存: 512mb

处理器: PIII 750 MHz

工具: .NET SDK Beta 2

数据库: SQL 服务器 2000 的 Pubs 数据库

[配置二]

操作系统: Windows XP Professional

计算机:Network! 3000 笔记本

內存:256mb

处理器: PIII 850 MHz

工具:.NET Final

数据库:MSDE 的 Pubs 数据库

简单的数据检索

我们首先要做的是通过 SQLAdapter 向数据库提交两个查询语句。

本例中,SQLAdapter 使用由两个 select 语句组成的 SQL 命令分别向 Pubs 数据库中的两个 table 发出查询请求:

string sSQL = "SELECT Pub_Id, Title, Price FROM; SELECT Pub_ID, Pub_Name FROM Publishers"

在 fill 模式下, SQLAdapter 将在查询命令前插入 sp_executesql ,再以 RPC 的形式一并提交给数据库:

Exec sp_executesql

N'SELECT Pub_Id, Title, Price FROM Titles; SELECT Pub_ID, Pub_Name FROM Publishers'

数据库也通过 RPC 返回两个 rowset。在 Dataset 中,rowset 与基本表是一一对应的。不幸的是,在 fill 模式下无法对这些基本表命名。相反,它为所有基本表提供一个共同的基本名。事实上,基本名就是第一个基本表的名字。随后的基本表命名都是在基本名后面加上一个不同的数字以互相区别,例如:Titles ,Titles1等。但是,通过简单的属性设置就能给所有基本表命名了:

daTest.Fill(dsTest, "Titles")

dsTest.Tables[1].TableName = "Publishers"

这种显式命名有助于基本表的处理和引用。

关于存储过程

在 ADO.NET 中如何使用存储过程?天,太复杂了!但我还是要简单地介绍一两点,为以后讨论层次数据作个铺垫吧!

利用存储过程同时获取多个行集(rowset)的方法有两种。

第一种方法,是“一个存储过程,多个输出行集”。例如,我们可以在前一个例子的基础上增加一个存储过程,将两条 select 语句包含进去:

CREATE PROCEDURE [dbo].[TitlesPerPublisher]

AS

Begin

SELECT Pub_Id, Title, Price FROM Titles

SELECT Pub_ID, Pub_Name FROM Publishers

End

够简单吧!这段代码提交两个 select 语句,因而将返回两个行集。

为了提高效率,我们可以借助 dataAdapter 的 Selectcommand 属性设置指令类型为

CommandType.StoredProcedure :

daHDAta = new SqlDataAdapter(sSQLCmd, cnstring)

dahData.SelectCommand.CommandType = CommandType.StoredProcedure

因为这样可以指示 dataAdapter 使用效率较高的 t-sql 语句 Exec 执行存储过程。假如省略这一步,dataAdapter 就以低效的 sp_executesql 执行它了。

第二种方法,是“两个存储过程,两个输出行集”。然而,此法造成数据往返传递,况且无论数据转输抑或 RPC 建立都是耗时过程,效率自然大打折扣。

由此我们得出结论:争取用一个存储过程返回全部行集 。就本例而言,最简单的做法莫过于用一个新过程捆绑两个存储过程。此法或许不尽完美,但是别忘了,这是“最简单”的。

至于如何在应用程序和 ADO.NET 中同时调用两个存储过程,由于篇幅有限,请自行参考有关 sqlCommand 对象的文章。

关系

为了处理现实中的层次数据,必须理清基本表之间的关系。借助 Dataset 的关系集合很轻易建立起关系。语法简洁明了,应该不成问题:

public void Add(DataRelation);

public virtual DataRelation Add(DataColumn, DataColumn);

public virtual DataRelation Add(DataColumn[], DataColumn[]);

public virtual DataRelation Add(string, DataColumn, DataColumn);

public virtual DataRelation Add(string, DataColumn[], DataColumn[]);

public virtual DataRelation Add(string, DataColumn, DataColumn, bool);

public virtual DataRelation Add(string, DataColumn[], DataColumn[], bool);

为了建立关系,必须提供一个关系名字符串和至少两个列。假如关系已经存在,或者列有问题 (比如它们不存在),则运行环境将产生一个异常。详情请见 .NET 框架 SDK 。

下列代码在现有的基本表之间新增了一个简单的关系:

dsTest.Relations.Add("PuBTitles",

dsTest.Tables["Publishers"].Columns["Pub_ID"],

dsTest.Tables["Titles"].Columns["Pub_ID"])

此代码在名为 PubTitles 的关系集合中创建了一个 relation 对象和一个关系:Publishers.Pub_ID 是父表,而 Titles.Pub_id 是子表。

显示数据

为了选取子列,datarow 对象提供了一个 GetChildRows 方法,它的参数是关系名或许关系对象名:

public DataRow[] GetChildRows(DataRelation);

public DataRow[] GetChildRows(string);

public DataRow[] GetChildRows(DataRelation, DataRowVersion);

public DataRow[] GetChildRows(string, DataRowVersion);

类似的方法还有 GetParentRow 和 GetParentRows 。它们根据子列返回父列的名字。

现在有了 GetChildRows 方法,就向数据进军吧! GetChildRows 返回一个 DataRowCollection 对象,后者的父类 InternalDataCollectionBase 是对 ICollection 和 IEnumerable 的具体实现。

接下来的循环处理只是举手之劳了。下列代码演示了显示数据关系的一种简单方法:

foreach(DataRow drPublisher in dtPublishers.Rows)

{

Console.WriteLine(drPublisher["Pub_Id"] + "\t" + drPublisher["Pub_Name"]);

Console.WriteLine("=====================");

foreach(DataRow drTitle in drPublisher.GetChildRows("PubTitles"))

{

Console.Write(drTitle["Title"] + "\t");

Console.Write((drTitle["price"].ToString() != null ? drTitle["price"] : "n/a"));

}

}

当然,也可明确指定一个 relation 对象:

DataRelation drPubsTitles = dsHData.Relations.Add("PubTitles",

dtPublishers.Columns["Pub_ID"],

dsHData.Tables["Titles"].Columns["Pub_ID"]);

foreach(DataRow drPublisher in dtPublishers.Rows)

{

Console.WriteLine(drPublisher["Pub_Id"] + "\t" + drPublisher["Pub_Name"]);

Console.WriteLine("=====================");

foreach(DataRow drTitle in drPublisher.GetChildRows(drPubsTitles))

{

Console.Write(drTitle["Title"] + "\t");

Console.Write((drTitle["price"].ToString() != null ? drTitle["price"] : "n/a"));

}

}

ADO.NET 能让程序员在数据表中创建自定义视图。这是由 DataView 类实现的:

public class DataView : MarshalByValueComponent, IBindingList,

IList, ICollection, IEnumerable, ITypedList, ISupportInitialize

当然,限于篇幅,这里仅仅列举了部分函数。

数据视图提供了两个有趣的属性:RowFilter 和 Sort 。RowFilter 与 ADO recordset 对象的 Filter 属性相似,它相当于与 SQL 语法中的 WHERE 语句,能够筛去匹配的列:

dtPublishers.DefaultView.RowFilter="Pub_ID < 2000";

最终得到的列被置于 DataRowView 集合中,因此能用 for each 语句循环处理它们。

Sort 属性用于指定输出数据的排序方式。它与 SQL 语法中的 ORDER BY 命令相似:

dtPublishers.DefaultView.Sort="PUB_ID Desc";

每个基本表对应一个 DataView 对象,上述DefaultView 就是其属性。于是,只需做些小小的修改,我们就能有选择地循环显示数据了。

foreach(DataRow drPublisher in dtPublishers.Rows)

{

Console.WriteLine(drPublisher["Pub_Id"] + "\t" + drPublisher["Pub_Name"]);

Console.WriteLine("=====================");

foreach(DataRow drTitle in drPublisher.GetChildRows("PubTitles"))

{

Console.Write(drTitle["Title"] + "\t");

Console.Write((drTitle["price"].ToString() != null ? drTitle["price"] : "n/a"));

}

}

结论

ADO.NET 大大简化了层次数据的处理,并且提供了改良的方案。

读过本文,是否跃跃欲试呢?若要追求更强的功能,恐怕还得另请高明了。

本文没有考虑性能优化,因为我们讨论的 SDK 还是 beta 2 版。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有