zoukankan      html  css  js  c++  java
  • ADO.NET的记忆碎片(三)

    接着ADO.NET的记忆碎片(二)继续

    DataAdapter类
    主要是在数据源以及DataSet 之间执行数据传输的工作,它可以透过Command 对象下达命令后,并将取得的数据放入DataSet 对象中。这个对象是架构在Command对象上,并提供了许多配合DataSet 使用的功能。
    构造一个DataAdapter对象有三方法:

    string strConn ="...";//连接字符串
    string strSql = "select * from MytableName1";
    SqlConnection cn = new SqlConnection(strConn);
    SqlCommand cmd = new SqlCommand(strSql,cn);
    1、SqlDataAdapter da1 = new SqlDataAdapter(strSql,strConn);
    2、SqlDataAdapter da2 = new SqlDataAdapter(strSql,cn);
    3、SqlDataAdapter da3 = new SqlDataAdapter(cmd);

    其实这三种方法很多时候可以互换使用,不过第一种有一些美中不足,当需要多次实例化的时候,并且这个strConn链接字符串也是一样的时候,会带来一个小问题,假设DataAdapter实例化了N次,那么也会实例化N个不同Connection的链接,其实我们只要一个这样的Connection的链接就好了,明显这是没有必要的性能损耗,2、3这两种方法可以显示的指定Connection实例,可以避免这样的问题。
    看看构造好了的SqlDataAdapter怎样将查询的结果存储在DataSet实例中呢,可是使用Fill()方法:

    DataSet ds = new DataSet();
    da.Fill(ds);
    foreach(DataRow row in ds.Tables[0].Rows)
    {
        Console.WriteLine("{0}--{1}",row[0],row["CustomerName"]);
    }

    关于Fill()方法的一个小说明:其实当程序进入Fill()方法后,会先检查Connection是否打开,要是打开,就可以继续数据的处理,最后推出Fill()方法;要是没有打开,就会先打开Connection链接,然后处理数据,在退出方法之前,关闭Connection链接,在Fill()方法的前后Connection状态是没有改变的,Fill()的聚合性很强的,用起来很简单。看看下面的代码:

    cn.Close();
    DataSet ds1 = new DataSet();
    DataSet ds2 = new DataSet();
    da.Fill(ds1);
    da.Fill(ds2);

    可以看到Connection是关闭着的,不过Fill()还是很好的完成了数据的处理,但是我们知道,其实上面的代码性能是可以进一步提升的,因为在调用Fill()方法两次中,对Connection实例进行了:Open();Close();Open();Close();的两次调用,可以把代码改进:

    cn.Close();
    DataSet ds1 = new DataSet();
    DataSet ds2 = new DataSet();
    cn.Open();
    da.Fill(ds1);
    da.Fill(ds2);
    cn.Close();

     我们看看存储在DataSet中的DataTable的名称是什么:

    Console.WriteLine("{0}",ds.Tables[0].TableName);

     会看到是“Table”。这个结果并不能让我们兴奋,为什么是这个名称?因为,SqlDataAdapter在背后是隐式创建了一个SqlDataReader,以获得查询的结果。在SqlDataAdapter查第一行数据之前,它会收集SqlDataReader的架构的信息,已确定列名称和类型,但是在默认的情况下,查询引用的表名称不能通过SqlDataReader来获得。所以在SqlDataReader中就会赋予了“Table”作为查询结果的表名称,最后导致了上面的这个结果。我们可以使用TableMappings这个属性改变这个纠结的现象:

    DataSet ds = new DataSet();
    da.TableMappings.Add("Table","MyTableName");
    da.Fill(ds);
    Console.WriteLine("{0}",ds.Tables[0].TableName);//会输出MyTableName

     Add()方法中两个参数,第一个参数是表示数据库中的表名称,第二个参数是表示DataSet中的表名称。因为SqlDataReader不能获得真的表名,所以赋予了“Table”作为查询结果的表名称,为了性能更好,这也是没有办法的事情。
    Fill()方法的重载:

    DataSet ds = new DataSet();
    DataTable table = new DataTable();
    1、da.Fill(ds);
    2、da.Fill(ds,"MyTableName");//表示存储在DataSet中的表名称是MyTableName,是da.TableMappings.Add("Table","MyTableName");da.Fill(ds);的语法唐
    3、da.Fill(table);

     希望将查询的结果映到自己设置的DataSet里,使用TableMappings和ColumnMappings的设置完成自己想要的:

    DataTableMapping tableMap;
    tableMap=da.TableMappings.Add("Table","MyTableName");
    tableMap.ColumnMappings.Add("EmpID","MyEmpID");
    tableMap.ColumnMappings.Add("EmpName","MyEmpName");

     Add()方法中两个参数,第一个参数是表示数据库中的表名称,第二个参数是表示DataSet中的表名称。SqlDataReader可以获得列名称和类型,不过不能获得表名称。然后只要执行Fill()方法,就可以在DataSet中看到查询的结果并且是自己设置的表名和列名:

    da.Fill(ds);
    Console.WriteLine("{0}",ds.Tables[0].TableName);
    foreach(DataColumn col in ds.Tables[0].Columns)
    {
        Console.WriteLine("{0}",col.Name);
    }

    使用批量查询
    有时候我们在一次查询中返回多个表结果:

    string strConn ="...";//连接字符串
    string strSql = "select * from MytableName1;"+"select * from MytableName2";
    SqlDataAdapter da = new SqlDataAdapter(strSql,strConn);
    da.TableMappings.Add("Table","MyTableName1");
    da.TableMappings.Add("Table1","MyTableName2");
    DataSet ds = new DataSet();
    da.Fill(ds);
    foreach(DataTable table in ds.Tables)
    {
        Console.WriteLine("{0}",table.TableName);
    }

    从中可以看出来MyTableName1、MyTableName1是我们为结果中的两个表命名,而Table和Table1是SqlDataReader不能获得数据库的表名,自己给添加的。最后说一句,DataAdapter背后是隐式的创建了DataReader来获取结果集的。


     

  • 相关阅读:
    年轻人绝对不懂的人际关系经验
    MRCPv2在电信智能语音识别业务中的应用
    S3 介绍
    RGW 学习 前言
    CEPH 自动化测试用例介绍
    CentOS7使用yum安装ceph rpm包
    Placement_pools on Rados-GW
    ceph log机制
    bucket list 函数解析
    ceph 初始化函数解析
  • 原文地址:https://www.cnblogs.com/lmfeng/p/2271930.html
Copyright © 2011-2022 走看看