SqlDataAdapter.Fill(dt) 和SqlDataReader + dt.Load()的差异

DataTable中的dt.Load()方法

复制代码
using (SqlDataReader Dr = sqlcomm.ExecuteReader())
        {
            // 把 Reader 的 Schema 加载到 DataTable(自动创建列)
            dt.Load(Dr);
        }

dt.Load(Dr); 这句代码到底干了什么? 它相当于直接把"传送带"的出口,插进了"空仓库"的门里! DataTable 极其聪明,当它执行 Load() 方法时,它会自动完成两步神操作:

  1. 先看图纸建货架(加载 Schema) :它会先看一眼传送带送来的"货物规格说明书(数据库表的列名、数据类型)",然后瞬间在自己的内存里自动建好一模一样的列(Columns) 。你完全不需要像之前那样手动去 dt.Columns.Add(...)

  2. 全自动卸货(填充 Rows) :建好列之后,它会自动让传送带 (Dr.Read()) 疯狂转动,把所有传送过来的数据一行不落地装进自己的 Rows 集合里,直到传送带上没货为止。

"既然有 SqlDataAdapter.Fill(dt) 这么爽的全自动包工头,为什么还要用 SqlDataReader + dt.Load() 这种写法呢?"

这叫"没有中间商赚差价"!

  • SqlDataAdapter.Fill()(包工头模式) : 你把命令交给包工头,包工头在底层其实也是去偷偷创建了一个 SqlCommand,又偷偷创建了一个 SqlDataReader,最后偷偷把数据塞进表里。它干活很全面,但因为封装得太厚,内存和性能开销相对大一点点

  • dt.Load(Dr)(极客直连模式) : 你省去了创建 SqlDataAdapter 对象的开销,直接操控底层最快的读取器 (SqlDataReader)。这种写法在处理中大型数据查询 时,执行速度会比 DataAdapter 更快,内存占用也更干净!

三、 唯一的高频"翻车坑点"(极其重要!)

既然你辞退了全自动的"包工头",决定亲自指挥,那你就必须承担起所有的责任!

包工头 SqlDataAdapter 最大的好处是会自动帮你打开和关闭 SqlConnection 连接 。 但是在你这套组合技里,不会有人帮你关连接!

复制代码
C#
DataTable dt = new DataTable();

// 第一层防弹衣:保护网络连接
using (SqlConnection conn = new SqlConnection(connStr))
{
    // 必须要手动打开连接!
    conn.Open(); 

    // 第二层防弹衣:保护卡车指令
    using (SqlCommand sqlcomm = new SqlCommand("SELECT * FROM Users WHERE Age > @Age", conn))
    {
        sqlcomm.Parameters.Add("@Age", SqlDbType.Int).Value = 18;

        // 第三层防弹衣:保护传送带(就是你发给我的这段)
        using (SqlDataReader Dr = sqlcomm.ExecuteReader())
        {
            // 完美卸货!自动建表头,自动填数据!
            dt.Load(Dr); 
        } // 离开大括号,Dr 传送带安全拆除
    } // 离开大括号,sqlcomm 卡车安全销毁
} // 离开大括号,conn 物理连接安全还给连接池!

// 此时断网了,但数据已经全在 dt 里了,你可以把它拿去绑定 WPF 界面了!
return dt;

// 5. 🌟 祭出作弊神器:SqlCommandBuilder 
 // 只要你给了 SelectCommand,它能根据 Select 自动逆向生成 Insert/Update/Delete 语句!
  SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

using System.Data;
using System.Data.SqlClient;

public void OfflineDataSyncDemo()
{
    string connStr = "Server=.;Database=MyCorpDB;Integrated Security=True;";
    // 1. 只写一句查询 SQL(作为基础图纸)
    string selectSql = "SELECT UserId, UserName, Age FROM Users";

    using (SqlConnection conn = new SqlConnection(connStr))
    {
        // 2. 召唤桥接器(物流大队长)!直接把图纸和路交给他
        SqlDataAdapter adapter = new SqlDataAdapter(selectSql, conn);

        // 3. 在本地内存里建一个空仓库
        DataTable dt = new DataTable();

        // 4. 【绝招一:拉货】全自动拉取,根本不需要写 conn.Open() !
        adapter.Fill(dt);
        
        // ========= 此时,网络已经断开了!你可以随便玩内存里的 dt =========
        
        // 假设我们在内存里改了第一行用户的名字 (模拟在界面上修改)
        dt.Rows[0]["UserName"] = "被修改的新名字";
        
        // 假设我们在内存里新增了一个用户
        DataRow newRow = dt.NewRow();
        newRow["UserId"] = 999;
        newRow["UserName"] = "新来的萌新";
        newRow["Age"] = 18;
        dt.Rows.Add(newRow);

        // ========= 玩够了,准备同步回数据库 =========

        // 5. 🌟 祭出作弊神器:SqlCommandBuilder 
        // 只要你给了 SelectCommand,它能根据 Select 自动逆向生成 Insert/Update/Delete 语句!
        SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

        try
        {
            // 6. 【绝招二:同步】一键把刚才所有的增删改操作,全部推回真实数据库!
            int changedCount = adapter.Update(dt);
            Console.WriteLine($"太帅了!成功同步了 {changedCount} 条改动到数据库!");
        }
        catch(Exception ex)
        {
            Console.WriteLine("同步失败,可能是并发冲突:" + ex.Message);
        }
    }
}
相关推荐
迷枫71213 小时前
达梦数据库安全管理与访问控制
数据库
潇湘秦13 小时前
OEM 13c Release 5 补丁升级记录
数据库·oracle
图特摩斯科技13 小时前
原生本体数据库AbutionGraph,世界模型/本体智能应用 底座
数据库·人工智能·知识图谱·本体论·palantir·ontology
潇湘秦13 小时前
Oracle 数据库SQL优化指南
数据库·sql·oracle
j7~14 小时前
【MYSQL】 内置函数--详解
数据库·mysql·字符串函数·内置函数·日期函数·数学函数
whn197714 小时前
ORACLE异常sql解析的案例
数据库·sql·oracle
夏贰四14 小时前
用好数据建模工具能解决哪些问题?如何正确选用建模工具?
大数据·数据库·数学建模·数据建模工具
小欣加油14 小时前
Hadoop开发环境搭建
大数据·数据库·hadoop
我是一颗柠檬14 小时前
【MySQL全面教学】MySQL存储过程与函数Day11(2026年)
数据库·后端·mysql