使用ADO.NET轻松操纵数据库(二)
2024-07-21 02:07:54
供稿:网友
首先,ado.net中使用了dataadapter 来处理与数据库的联机与脱机。当时开发人员设计了dataadapter是为了能够处理脱机数据,方便操作,关于这一点,只要调用其fill()方法即可,这时会在dataset中创建一个新的名为“table“的datatable.要重新指定名可用dataadapter.fill(dataset,“tabelname“)。此时connection也关闭了。dataadapter既可以用来提交查询,并将结果存储到dataset中,也可以用来向数据库传递更改。仅仅使用其update方法即可达到向数据库提交存储地datset中的更改。
dataadapter将查询的结果存储在dataset或datatable对象中,当执行这一过程的时候,dataadapter使用了一个command来与数据库通讯,并在内部使用了datareader来获取查询结果,最后才将结果复制到dataset新行中去。这也是fill的过程。如果有两个dataadapter对象,都使用相同的connection对象,在创建的时候就会创建两个connection对象,而不是同一个,这种情况的解决方案是:
sqlconnection con=new sqlconnection("server=localhost;database=northwind;trusted_connection=yes;")
sqldataadapter da=new sqldataadapter("select categoryid,description from categories",con);
sqldataadapter da=new sqldataadapter("select categoryid,description from customers",con);
而不是将查询字符串,单独写成一行。
有时候可能并不希望dataset中的架构与数据库中的架构相同,这种情况的解决方案之一是可以采用别名的方法,即select id as product id,amount as product amount from product;另外一种解决方案就是使用dataadapter提供的tablemappings集合机制,通过它就可以将查询结果映射到dataset结构中,这种方法更方便,更灵活。tablemappings属性返回一个datatablemappingscollection对象,其中包含了一组datatablemappings,只要dataset中相应的表名称与数据库中的表名相同,即可以使用它来创建一个映射(dataset中可以有多个表)。tablemappings里还有一个columnmappings属性,其用法与tablemappings相似。其原理是dataadapter从数据库读取数据后,利用datareader从结果集中获取列名称,有一点特别要注意,即只能获取列名称而无法获取表名称,dataadapter事先假定表名称为table,接着遇到映射语句则进行表映射。不说了,看代码:
datacolumnmapping colmap;
sqlconnection con=new sqlconnection("server=localhost;database=northwind;trusted_connection=yes;");
sqldataadapter da=new sqldataadapter("select categoryid,description from categories",con);
dataset ds=new dataset();
datatablemapping tblmap=da.tablemappings.add("table","ca"); //这里table为关键,映射表名为ca
colmap=tblmap.columnmappings.add("categoryid","id"); //映射列表
colmap=tblmap.columnmappings.add("description","描述");
// response.write(tblmap.datasettable.tostring());
da.fill(ds);
datatable dt=ds.tables["ca"]; //这里是映射后的表名,如果仍为数据库的表名,则无效,特别注意
this.datagrid1.datasource=dt;
this.datagrid1.databind();
运行代码后就会发现datagrid1上的列名为id和描述 (^_^)
(注:使用datatablemapping 之前要前导入名空间system.data.common;)
还可以使用addrange方法来简化表和列的映射:(一些代码同上面)
.......
datatablemapping tblmap=da.tablemappings.add("table","ca"); datacolumnmapping[] colmaparray=new datacolumnmapping[]{new datacolumnmapping("categoryid","产 品号"),new datacolumnmapping("description","描述")}; tblmap.columnmappings.addrange(colmaparray);
......
这种映射关系只能从数据库中读取展示给用户,如果要将映射后的table的更改提交给数据库,这时库发现其中列与库中列不同,便会发生异常,dataadapter 同时也提供了missingmappingaction属性来处理。
dataadapter1.missingmappingaction=missingmappingaction.passthrough/ignore/error
它接受missingmappingaction的枚举值,passthrough这个值表示如果在库中找不到与dataset中相同列的话,就将此列映射到库中,ignore枚举值表示忽略示出现的列,error表示找不到相应的列则抛出异常。
分页:
分页在应用中是常有的事,而dataadapter本身也提供了分页的简单功能,如:dataadapter1.fill(dataset,startrow,rownum,“tablename“)这种功能用于数据量较小的查询就可以,但当有大量数据的时候,就会发现这种分页的问题的存在。它的原理是假如有一百行数据,分成十页,每页十行,当获取每一页的时候,返回前10行,再接着,第二页,删除了前10行而获取接下的10行,在这一次中,只是为了获取10行数据,但数据库却返回了20行,依此类推,第10页的时候就会返回100行,而dataadapter本身就帮我们删除了90行,因为我们看上去返回的还是10行,这种性能太低。因此本篇继续介绍另外一种性能较高的分页方法。实际上这种分页方法是将上一页最后一行的键值存储下来,直接在sql语句中就过滤掉了,不象前面那种到dataadapter这边才过滤掉。例:
con=new sqlconnection("server=localhost;database=northwind;trusted_connection=yes;");
da=new sqldataadapter("select top 50 customerid,companyname from customers where customerid>'bottm'",con);
ds=new dataset();
da.fill(ds,"categories");
this.datagrid1.datasource=ds.tables["categories"]; this.datagrid1.databind();
con.close();
这里假如上一页最后一个键值为”bottm”,可以将它用参数替代掉,这样就查出了在'bottm'之后的50行。这种方法实现简单效率也高。