文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一个有趣的问题,你知道SqlDataAdapter中的Fill是怎么实现的吗

2024-11-30 07:29

关注
var dt = new DataTable();
    SqlDataAdapter adapter = new SqlDataAdapter(new SqlCommand());
    adapter.Fill(dt);

是不是很眼熟哈,或许你也已经多年不见了,犹记得那时候为了能从数据库获取数据,第一种方法就是采用 SqlDataReader 一行一行从数据库读取,而且还要操心 Reader 的 close 问题,第二种方法为了避免麻烦,就直接使用了本篇说到的 SqlDataAdapter ,简单粗暴,啥也不用操心,对了,不知道您是否和我一样对这个 Fill 方法很好奇呢?,它是如何将数据塞入到 DataTable 中的呢?也是用的 SqlDataReader 吗?而且 Fill 还有好几个扩展方法,哈哈,本篇就逐个聊一聊,就当回顾经典啦!

二、对Fill方法的探究

1. 使用 dnspy 查看Fill源码

dnspy小工具大家可以到GitHub上面去下载一下,这里就不具体说啦,接下来追一下Fill的最上层实现,如下代码:

public int Fill(DataTable dataTable)
        {
            IntPtr intPtr;
            Bid.ScopeEnter(out intPtr, " %d#, dataTable\n", base.ObjectID);
            int result;
            try
            {
                DataTable[] dataTables = new DataTable[]
                {
                    dataTable
                };
                IDbCommand selectCommand = this._IDbDataAdapter.SelectCommand;
                CommandBehavior fillCommandBehavior = this.FillCommandBehavior;
                result = this.Fill(dataTables, 0, 0, selectCommand, fillCommandBehavior);
            }
            finally
            {
                Bid.ScopeLeave(ref intPtr);
            }
            return result;
        }

上面的代码比较关键的一个地方就是 IDbCommand selectCommand = this._IDbDataAdapter.SelectCommand; 这里的 SelectCommand 来自于哪里呢?来自于你 new SqlDataAdapter 的时候塞入的构造函数 SqlCommand,如下代码:

public SqlDataAdapter(SqlCommand selectCommand) : this()
        {
            this.SelectCommand = selectCommand;
        }

然后继续往下看 this.Fill 方法,代码简化后如下:

protected virtual int Fill(DataTable[] dataTables, int startRecord, int maxRecords, IDbCommand command, CommandBehavior behavior)
        {
            result = this.FillInternal(null, dataTables, startRecord, maxRecords, null, command, behavior);

            return result;
        }

上面这段代码没啥好说的,继续往下追踪 this.FillInternal 方法,简化后如下:

private int FillInternal(DataSet dataset, DataTable[] datatables, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior)
        {
            int result = 0;
            try
            {
                IDbConnection connection = DbDataAdapter.GetConnection3(this, command, "Fill");
                try
                {
                    IDataReader dataReader = null;
                    try
                    {
                        dataReader = command.ExecuteReader(behavior);
                        result = this.Fill(datatables, dataReader, startRecord, maxRecords);
                    }
                    finally
                    {
                        if (dataReader != null)    dataReader.Dispose();
                    }
                }
                finally
                {
                    DbDataAdapter.QuietClose(connection, originalState);
                }
            }
            finally
            {
                if (flag)
                {
                    command.Transaction = null;
                    command.Connection = null;
                }
            }
            return result;
        }

大家可以仔细研读一下上面的代码,挺有意思的,至少你可以获取以下两点信息:

protected virtual int Fill(DataTable[] dataTables, IDataReader dataReader, int startRecord, int maxRecords)
        {
            try
            {
                int num = 0;
                bool flag = false;
                DataSet dataSet = dataTables[0].DataSet;
                int num2 = 0;
                while (num2 < dataTables.Length && !dataReader.IsClosed)
                {
                    DataReaderContainer dataReaderContainer = DataReaderContainer.Create(dataReader, this.ReturnProviderSpecificTypes);
                    if (num2 == 0)
                    {
                        bool flag2;
                        do
                        {
                            flag2 = this.FillNextResult(dataReaderContainer);
                        }
                        while (flag2 && dataReaderContainer.FieldCount <= 0);
                        }
                    }
                result = num;
            }
            return result;
        }

从上面代码可以看到, dataReader 被封装到了 DataReaderContainer 中,用 FillNextResult 判断是否还有批语句sql,从而方便生成多个 datatable 对象,最后就是填充 DataTable ,当然就是用 dataReader.Read()啦,不信你可以一直往里面追嘛,如下代码:

private int FillLoadDataRow(SchemaMapping mapping)
        {
            int num = 0;
            DataReaderContainer dataReader = mapping.DataReader;

            while (dataReader.Read())
            {
                mapping.LoadDataRow();
                num++;
            }
            return num;
        }

到这里你应该意识到:DataReader 的性能肯定比 Fill 到 DataTable 要高的太多,所以它和灵活性两者之间看您取舍了哈。

三、Fill 的其他重载方法

刚才给大家介绍的是带有 DataTable 参数的重载,其实除了这个还有另外四种重载方法,如下图:

public override int Fill(DataSet dataSet);
    public int Fill(DataSet dataSet, string srcTable);
    public int Fill(DataSet dataSet, int startRecord, int maxRecords, string srcTable);
    public int Fill(int startRecord, int maxRecords, params DataTable[] dataTables);

1. startRecord 和 maxRecords

从字面意思看就是想从指定的位置 (startRecord) 开始读,然后最多读取 maxRecords 条记录,很好理解,我们知道 reader() 是只读向前的,然后一起看一下源码底层是怎么实现的。

图片

从上图中可以看出,还是很简单的哈,踢掉 startRecord 个 reader(),然后再只读向前获取最多 maxRecords 条记录。

2. dataSet 和 srcTable

这里的 srcTable 是什么意思呢?从 vs 中看是这样的: The name of the source table to use for table mapping. 乍一看也不是特别清楚,没关系,我们直接看源码就好啦,反正我也没测试,嘿嘿。

图片

从上图中你应该明白大概意思就是给你 dataset 中的 datatable 取名字,比如:name= 学生表, 那么database中的的 tablename依次是: 学生表,学生表1,学生表2 ..., 这样你就可以索引获取表的名字了哈,如下代码所示:

DataSet dataSet = new DataSet();
        dataSet.Tables.Add(new DataTable("学生表"));
        var tb = dataSet.Tables["学生表"];

四、总结

本篇就聊这么多吧,算是解了多年之前我的一个好奇心,希望本篇对您有帮助。

来源:一线码农聊技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯