首页 > 编程 > .NET > 正文

ADO.NET中的多数据表操作浅析—读取

2024-07-10 13:03:12
字体:
来源:转载
供稿:网友
ado.net中的多数据表操作浅析—读取

作者:郑佐??????? 2004-8-5

???????? 在开发基于.net平台的数据库应用程序时,我们一般都会用到dataset,作为ado.net的核心类它为我们提供了强大的功能,而整个看上去就像是放在内存内的一个小型数据库,内部包括了datatable、dataview、datarow、datacolumn、constraint以及datarelation。当初看到它时真的是有点兴奋。

???????? 下面根据我的一些经验来举例说明在ado.net中的多表填充、关联表更新以及多个command对象执行过程中启用事务的操作。欢迎大家交流,或在blog上留言。

????????

一、准备工作

???????? 对于northwind数据库大家都比较熟悉,所以这里拿它为例,我把customers(客户表)、orders(订单表)、order details(订单详细表)合起来建立了一个类型化的数据集,类型名称为datasetorders,每个表只包括一些字段,下面是在visual studio .net中建立的一个截图:

?

图1-1

上面建立了两个关系表示为customers —> orders —>order details。因为orders表的orderid字段为自动增长列,这里把就把它的autoincrementseed和autoincrementstep值设置成了-1,这在实际添加订单的过程中可能会比较明显,不过不设也没问题。

????????

二.填充数据集

建立一个窗体程序来演示实际的操作,界面如下:



图2-1

整个应用程序就是一个form,上面的三个datagrid分别用来显示相关表的数据,不过他们是互动的。另外的两个单选框用来决定更新数据的方式,两个按钮正如他们的名称来完成相应的功能。

这里我们用一个dataadapter来完成数据集的填充,执行的存储过程如下:

create procedure getcustomerordersinfo

as

select customerid,companyname,contactname from customers where customerid like 'a%'

?

select orderid,orderdate,customerid from orders? where customerid in

(select customerid from customers where customerid like 'a%')

?

select orderid,productid,unitprice,quantity,discount from [order details] where orderid in

(select orderid from orders? where customerid in

(select customerid from customers where customerid like 'a%'))

?

go

?

为了减少数据量,这里只取了customerid以’a’开头的数据。

建立dataaccess类来管理窗体同数据层的交互:

using system;

using system.data;

using system.data.sqlclient;

using microsoft.applicationblocks.data;

?

namespace winformtest

{

???? public class dataaccess

???? {

???????? private string _connstring = "data source=(local);initial catalog=northwind;uid=csharp;pwd=c#.net2004;";

???????? private sqlconnection _conn;

???????? ///构造函数

public dataaccess()

???????? {

????????????? _conn = new sqlconnection(_connstring);

}

下面的函数完成单个数据适配器来完成数据集的填充,

public void fillcustomerordersinfo(datasetorders ds)

???? ???? {

????????????? sqlcommand comm = new sqlcommand("getcustomerordersinfo",_conn);

????????????? comm.commandtype = commandtype.storedprocedure;

????????????? sqldataadapter dataadapter = new sqldataadapter(comm);

????????????? dataadapter.tablemappings.add("table","customers");

????????????? dataadapter.tablemappings.add("table1","orders");

????????????? dataadapter.tablemappings.add("table2","order details");

????????????? dataadapter.fill(ds);

???????? }

如果使用sqlhelper来填充那就更简单了,

???????? public void fillcustomerordersinfowithsqlhelper(datasetorders ds)

???????? {???????????? sqlhelper.filldataset(_connstring,commandtype.storedprocedure,"getcustomerordersinfo",ds,new string[]{"customers","orders","order details"});

???????? }

叉开话题提一下,data access application block 2.0中的sqlhelper.filldataset这个方法超过两个表的填充时会出现错误,其实里面的逻辑是错的,只不过两个表的时候刚好凑巧,下面是从里面截的代码:

private static void filldataset(sqlconnection connection, sqltransaction transaction, commandtype commandtype,

????????????? string commandtext, dataset dataset, string[] tablenames,

????????????? params sqlparameter[] commandparameters)

???????? {

????????????? if( connection == null ) throw new argumentnullexception( "connection" );

????????????? if( dataset == null ) throw new argumentnullexception( "dataset" );

????????????? sqlcommand command = new sqlcommand();

????????????? bool mustcloseconnection = false;

????????????? preparecommand(command, connection, transaction, commandtype, commandtext, commandparameters, out mustcloseconnection );

??? ????????? using( sqldataadapter dataadapter = new sqldataadapter(command) )

????????????? {

???????? ????????? if (tablenames != null && tablenames.length > 0)

?????????????????? {

?????????????????????? string tablename = "table";

?????????????????????? for (int index=0; index < tablenames.length; index++)

?????????????????????? {

??????????????????????????? if( tablenames[index] == null || tablenames[index].length == 0 )

???????????????????????????????? throw new argumentexception( "the tablenames parameter must contain a list of tables, a value was provided as null or empty string.", "tablenames" );

??????????????????????????? tablename += (index + 1).tostring();//这里出现错误

?????????????????????? }

?????????????????? }

?????????????????? dataadapter.fill(dataset);

?????????????????? command.parameters.clear();

????????????? }

????????????? if( mustcloseconnection )

?????????????????? connection.close();

???????? }

?

这里把tablename += (index + 1).tostring();修改成

dataadapter.tablemappings.add((index>0)?(tablename+index.tostring()):tablename, tablenames[index]);就能解决问题。

?

接下来看看窗体程序的代码:

public class form1 : system.windows.forms.form

???? {

???????? private dataaccess _dataaccess;

???????? private datasetorders _ds;

???????? //……

???????? //构造函数

???????? public form1()

???????? {

????????????? initializecomponent();

????????????? _dataaccess = new dataaccess();

????????????? _ds = new datasetorders();

????????????? _ds.enforceconstraints = false; //关闭约束检查,提高数据填充效率

????????????? this.datagridcustomers.datasource = _ds;

????????????? this.datagridcustomers.datamember = _ds.customers.tablename;

????????????? this.datagridorders.datasource = _ds;

????????????? this.datagridorders.datamember = _ds.customers.tablename+"."+_ds.customers.childrelations[0].relationname;

????????????? this.datagridorderdetails.datasource = _ds;

????????????? this.datagridorderdetails.datamember = _ds.customers.tablename+"."+_ds.customers.childrelations[0].relationname+"."+_ds.orders.childrelations[0].relationname;

???????? }

对于上面的三个表的动态关联,你也可以使用setdatabinding方法来完成数据的动态绑定,而不是分别指定datagride的datasource和datamemger属性。

this.datagridcustomers.setdatabinding(_ds,_ds.customers.tablename);

this.datagridorders.setdatabinding(_ds,_ds.customers.tablename+"."+_ds.customers.childrelations[0].relationname);

this.datagridorderdetails.setdatabinding(_ds,_ds.customers.tablename+"."+_ds.customers.childrelations[0].relationname+"."+_ds.orders.childrelations[0].relationname);

}

数据填充事件处理如下:????????????????????????

private void buttonfilldata_click(object sender, system.eventargs e)

???????? {

????????????? _ds.clear();//重新填充数据集

????????????? _dataaccess.fillcustomerordersinfo(_ds);

????????????? //_dataaccess.fillcustomerordersinfowithsqlhelper(_ds);

???????? }

执行上面的事件处理函数我们会看到数据显示到对应的datagrid上,如(图2-1)所示。

如果使用数据读取器获取多表纪录下面是实现的一种方式(参考):

sqlcommand comm = new sqlcommand("getcustomerordersinfo",_conn);

comm.commandtype = commandtype.storedprocedure;

_conn.open();

sqldatareader reader = comm.executereader();

do

{

???? while(reader.read())

???? {

???????? console.writeline(reader[0].tostring());//获取数据代码

???? }

}while(reader.nextresult());

console.readline();

_conn.close();

?

?




收集最实用的网页特效代码!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表