趣味理解ADO.NET对象模型
输水管——DataAdapter
DataAdapter提供连接DataSet对象和数据源的桥梁。DataAdapter使用Command对象在数据源中执行SQL命令,以便将数据加载到DataSet中,并使DataSet中数据的更改与数据源保持一致。
趣味理解
DataAdapter就像一根输水管,通过发动机,把水从水源输送到水库里进行保存。

1.创建SqlDataAdapter

(1)初始化SqlDataAdapter类的新实例。
string conString = "data source=127.0.0.1;Database=codematic;user id=sa;
        password=";
SqlConnection myConnection = new SqlConnection(conString);
SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "SELECT * FROM P_Product";
DataSet ds = new DataSet();
myConnection.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
adapter.Fill(ds, "ds");
myConnection.Close();
(2)使用指定的 SqlCommand 初始化 SqlDataAdapter 类的新实例。
string conString = "data source=127.0.0.1;Database=codematic;user id=sa;
        password=";
SqlConnection myConnection = new SqlConnection(conString);
DataSet ds = new DataSet();
SqlCommand cmd = myConnection.CreateCommand();
cmd.CommandText = "SELECT * FROM P_Product";
myConnection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds, "ds");
myConnection.Close();
(3)使用selectcommand字符串 和 SqlConnection对象初始化SqlDataAdapter 类的新实例。
string conString = "data source=127.0.0.1;Database=codematic;user id=sa;
password=";
string strSQL = "SELECT * FROM P_Product";
SqlConnection myConnection = new SqlConnection(conString);
DataSet ds = new DataSet();
myConnection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(strSQL, myConnection);
adapter.Fill(ds, "ds");
myConnection.Close();
(4)使用selectcommand字符串和一个连接字符串初始化SqlDataAdapter类的新实例。
string conString = "data source=127.0.0.1;Database=codematic;user id=sa;
password=";
string strSQL = "SELECT * FROM P_Product";           
DataSet ds = new DataSet();           
SqlDataAdapter adapter = new SqlDataAdapter(strSQL, conString);
adapter.Fill(ds, "ds");

2.DataAdapter和SqlConnection、SqlCommand建立关联

方式1:DataAdapter在构造参数时建立。
方式2:通过SelectCommand属性建立。
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(strSQL, myConnection);

5.1.6  输水管——DataReader

通过执行ExecuteReader方法可以返回一个DataReader 对象。DataReader以只进、只读方式返回数据,从而提高应用程序的性能。这样可以节省 DataSet 所使用的内存,并省去创建 DataSet 并填充其内容所需的处理。
趣味理解
DataReader 也是一种水管,和DataAdapter不同的是,DataReader不把水输送到水库里面,而是单向地直接把水送到需要水的用户那里或田地里,所以要比在水库中转一下更快。
(1)遍历DataReader结果集。
SqlDataReader dr = cmd.ExecuteReader();           
while (dr.Read())
{
    Response.Write(dr.GetInt32(0).ToString()+ ", "+ dr.GetString(1) + "<br>");
}
dr.Close();
(2)使用序数索引器。
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
    Response.Write(dr[0].ToString() + ", " + dr[1].ToString() + "<br>");
}
dr.Close();
(3)使用列名索引器。
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
    Response.Write(dr["ProductId"].ToString()+", "+dr["Name"].ToString());
}
dr.Close();
(4)使用类型访问器。
public char GetChar(int i); 获取指定列的单个字符串形式的值
public DateTime GetDateTime(int i); 获取指定列的 DateTime 对象形式的值
public short GetInt16(int i); 获取指定列的 16 位有符号整数形式的值
public string GetString(int i); 获取指定列的字符串形式的值
(5)得到DataReader的列信息。
dr.FieldCount     获取当前行中的列数
dr.GetFieldType(序号)   获取是对象的数据类型的 Type
dr.GetDataTypeName(序号)  获取源数据类型的名称
dr.GetName(序号)     获取指定列的名称
dr.GetOrdinal(序号)   在给定列名称的情况下获取列序号
(6)得到数据表的信息。
DataTable dt=dr.GetSchemaTable();
(7)操作多个结果集。
SqlDataReader dr = cmd.ExecuteReader();    
do
{
    while (dr.Read())
    {
        Response.Write(dr.GetInt32(0).ToString()+", "+dr.GetString(1));
    }
}
while(myReader.NextResult());//使数据读取器前进到下一个结果集
dr.Close();
下面是一些使用DataReader获得最佳性能的技巧。
l         在使用带参数的Command前,必须关闭DataReader。
l         完成读数据之后一定要关闭DataReader。如果使用Connection只返回DataReader,那么关闭DataReader之后立刻关闭它。另外一个显式关闭Connection的方法是将CommandBehavior.CloseConnection传递给ExecuteReader方法,以确保关闭DataReader时相应的连接也被关闭。如果从一个方法返回DataReader,而且不能控制DataReader的相关连接的关闭,则这样做特别有用。
l         不能在层之间远程访问DataReader。DataReader是为已连接好的数据访问而设计的。
l         当访问列数据时,使用类型化访问器,例如GetString、GetInt32等。这使你不用将GetValue返回的Object强制转换成特定类型。
l         一个单一连接每次只能打开一个DataReader。如果想在相同的数据存储区上同时打开两个DataReader,则必须显式创建两个连接,每个DataReader一个。这是ADO.NET为池化连接的使用提供更多控制的一种方法。
l         在默认情况下,DataReader每次Read时都要将整行加载到内存。这允许在当前行内随机访问列。如果不需要这种随机访问,为了提高性能,则将CommandBehavior.SequentialAccess传递给ExecuteReader调用。这将DataReader的默认行为更改为仅在请求时将数据加载到内存。注意,CommandBehavior. SequentialAccess要求顺序访问返回的列。也就是说,一旦读过返回的列,就不能再读它的值了。
l         如果已经读取了来自DataReader的数据,但仍然有大量挂起的未读结果,则在关闭DataReader之前先要取消Command。因为取消Command可使服务器放弃这些结果,从而释放服务器的资源。

5.1.7  随用随关,释放资源

对于C#程序员来说,确保始终关闭Connection和DataReader对象的一个方便的方法就是使用using语句。using语句在离开自己的作用范围时,会自动调用被“使用”的对象的Dispose。例如:
string connectionString = "data source=127.0.0.1;Database=codematic;
user id=sa;password=";
using (SqlConnection myConnection = new SqlConnection(connectionString))
{
    SqlCommand cmd = myConnection.CreateCommand();
    cmd.CommandText = "SELECT * FROM P_Product";
    myConnection.Open();
    using (SqlDataReader dr = cmd.ExecuteReader())
    {
        while (dr.Read())
        {
            Response.Write(dr.GetInt32(0).ToString()+","+dr.GetString(1)+"<br>");
        }
}
}
 
 
《亮剑.NET: