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);
        }
    }
}
相关推荐
笃行3505 小时前
数据库性能优化的五处内核改造,KingbaseES 配了四件诊断工具
数据库
非优秀程序员7 小时前
第02章 杭电的英语老师与一台服务器|《互联网产品恩仇录》
数据库·node.js·代码规范
SelectDB12 小时前
SelectDB 是哪个公司的?是国产数据库吗?一篇讲清飞轮科技与 Apache Doris 的关系
数据库
这个DBA有点耶12 小时前
库内计算推理:一条SQL背后的算子融合,和外挂方案差了几次网络往返
数据库·人工智能·sql
这个DBA有点耶14 小时前
函数索引的“完全一致”有多苛刻:写法、字符集、类型,差一处就失效
数据库·mysql·代码规范
星恒随风14 小时前
MySQL 从零入门(三):表的约束详解
linux·服务器·数据库·笔记·mysql
Alluxio15 小时前
Alluxio + OCI:为 AI 工作负载实现亚毫秒访问延迟与可扩展吞吐
运维·数据库·人工智能·分布式·缓存·ai·语言模型
数据库急诊室_阿哲19 小时前
一次加索引建议的复核记录:从报告到签字
数据库·ai数据库
青瓦梦滋19 小时前
Redis主从复制
服务器·数据库·redis·缓存·bootstrap
慧都小妮子20 小时前
Wyn商业智能国产数据库适配:数据接入、分析缓存与审计日志验证清单
数据库·数据分析·数据可视化·审计日志·商业智能