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);
        }
    }
}
相关推荐
倔强的石头_2 小时前
《Kingbase护城河》——数据库存储空间全景探测与精细化瘦身实战
数据库
冬奇Lab15 小时前
每日一个开源项目(第134篇):Zvec - 阿里开源的嵌入式向量数据库,向量搜索界的 SQLite
数据库·人工智能·llm
ClouGence1 天前
Oracle CDC 架构优化:从主库直连到 DataGuard 备库同步
数据库·后端·oracle
无响应de神1 天前
三、用户与权限管理
数据库·mysql
麦聪聊数据2 天前
数据服务化时代:企业数据能力输出的核心路径
数据库
shushangyun_2 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
DARLING Zero two♡2 天前
【MySQL数据库】数据类型与表约束
数据库·mysql
曹牧2 天前
Oracle EXPLAIN PLAN
数据库·oracle
BD_Marathon2 天前
SQL学习指南——视图
数据库·sql
活宝小娜2 天前
mysql详细安装教程
数据库·mysql·adb