如果使用批处理SQL语句检索多个表并填充DataSet,第一个表用指定给Fill方法的表名命名。后面的表用指定给Fill方法的表名加上一个从1开始并且增量为1的数字命名。例如,如果运行下面的代码:
‘Visual Basic Dim da As SqlDataAdapter = New SqlDataAdapter(“SELECT * FROM Customers; SELECT * FROM Orders;”, myConnection) Dim ds As DataSet = New DataSet() da.Fill(ds, “Customers”)
//C# SqlDataAdapter da = new SqlDataAdapter(“SELECT * FROM Customers; SELECT * FROM Orders;”, myConnection); DataSet ds = new DataSet(); da.Fill(ds, “Customers”);
来自Customers表的数据放在名为“Customers”的DataTable中。来自Orders表的数据放在名为“Customers1”的DataTable中。
填充完DataSet之后,可以很容易地将“Customers1”表的TableName属性改为“Orders”。但是,后面的填充会导致“Customers”表被重新填充,而“Orders”表会被忽略,并创建另外一个“Customers1”表。为了对这种情况作出补救,创建一个DataTableMapping,将“Customers1”映射到“Orders”,并为其他后面的表创建其他的表映射。例如:
‘Visual Basic Dim da As SqlDataAdapter = New SqlDataAdapter(“SELECT * FROM Customers; SELECT * FROM Orders;”, myConnection) da.TableMappings.Add(“Customers1″, “Orders”) Dim ds As DataSet = New DataSet() da.Fill(ds, “Customers”)
//C# SqlDataAdapter da = new SqlDataAdapter(“SELECT * FROM Customers; SELECT * FROM Orders;”, myConnection); da.TableMappings.Add(“Customers1″, “Orders”); DataSet ds = new DataSet(); da.Fill(ds, “Customers”);
使用DataReader
下面是一些使用DataReader获得最佳性能的技巧,同时还回答了一些关于使用DataReader的常见问题。
1) 在访问相关Command的任何输出参数之前,必须关闭DataReader。
2) 完成读数据之后总是要关闭DataReader。如果使用Connection只是用于返回DataReader,那么关闭DataReader之后立刻关闭它。
另外一个显式关闭Connection的方法是将CommandBehavior.CloseConnection传递给ExecuteReader方法,以确保相关的连接在关闭DataReader时被关闭。如果从一个方法返回DataReader,而且不能控制DataReader或相关连接的关闭,则这样做特别有用。
1) 不能在层之间远程访问DataReader。DataReader是为已连接好的数据访问设计的。
2) 当访问列数据时,使用类型化访问器,例如,GetString、GetInt32等。这使您不用进行将GetValue返回的Object强制转换成特定类型所需的处理。
3) 一个单一连接每次只能打开一个DataReader。在ADO中,如果打开一个单一连接,并且请求两个使用只进、只读游标的记录集,那么ADO会在游标生存期内隐式打开第二个、未池化的到数据存储区的连接,然后再隐式关闭该连接。对于ADO.NET,“秘密”完成的动作很少。如果想在相同的数据存储区上同时打开两个DataReaders,就必须显式创建两个连接,每个DataReader一个。这是ADO.NET为池化连接的使用提供更多控制的一种方法。
4) 默认情况下,DataReader每次Read时都要将整行加载到内存。这允许在当前行内随机访问列。如果不需要这种随机访问,为了提高性能,就将CommandBehavior.SequentialAccess传递给ExecuteReader调用。这将DataReader的默认行为更改为仅在请求时将数据加载到内存。注意,CommandBehavior.SequentialAccess要求顺序访问返回的列。也就是说,一旦读过返回的列,就不能再读它的值了。
5) 如果已经完成读取来自DataReader的数据,但仍然有大量挂起的未读结果,就在调用DataReader的Close之前先调用Command的Cancel。调用DataReader的Close会导致在关闭游标之前检索挂起的结果并清空流。调用Command的Cancel会放弃服务器上的结果,这样,DataReader在关闭的时候就不必读这些结果。如果要从Command返回输出参数,还要调用Cancel放弃它们。如果需要读取任何输出参数,不要调用Command的Cancel,只要调用DataReader的Close即可。
二进制大对象(BLOB)
用DataReader检索二进制大对象(BLOB)时,应该将CommandBehavior.SequentialAccess传递给ExecuteReader方法调用。因为DataReader的默认行为是每次Read都将整行加载到内存,又因为BLOB值可能非常大,所以结果可能由于单个BLOB而使大量内存被用光。SequentialAccess将DataReader的行为设置为只加载请求的数据。然后还可以使用GetBytes或GetChars控制每次加载多少数据。
记住,使用SequentialAccess时,不能不按顺序访问DataReader返回的不同字段。也就是说,如果查询返回三列,其中第三列是BLOB,并且想访问前两列中的数据,就必须在访问BLOB数据之前先访问第一列的值,然后访问第二列的值。这是因为现在数据是顺序返回的,并且DataReader一旦读过该数据,该数据就不再可用。
使用命令