当前位置:首页 > 技术 > 正文内容

深入理解 ADO.NET 数据访问技术与实用工具类

访客 技术 2026年6月27日 1

ADO.NET 核心架构解析

ADO.NET 是 .NET 平台中用于与数据源交互的核心组件,它提供了一套完整的数据访问机制,支持关系型数据库(如 SQL Server、Oracle)和非关系型数据源的连接与操作。其设计兼顾高性能与灵活性,广泛应用于桌面、Web 和服务端开发。

关键组件详解

1. Connection 对象:建立数据库通信

Connection 类负责管理应用程序与数据库之间的连接。通过配置连接字符串(ConnectionString),可指定服务器地址、数据库名、身份验证方式等信息。

string connStr = "Server=localhost;Database=TestDB;User Id=sa;Password=123456;";
using (SqlConnection conn = new SqlConnection(connStr))
{
    conn.Open();
    // 执行后续操作
}

2. Command 对象:执行 SQL 指令

Command 用于向数据库发送 T-SQL 命令,支持增删改查及存储过程调用。常用方法包括:

  • ExecuteNonQuery():执行非查询语句(INSERT/UPDATE/DELETE),返回受影响行数。
  • ExecuteScalar():返回结果集中第一行第一列的值,常用于聚合函数查询。
  • ExecuteReader():获取只读、前向的数据流,适合处理大量记录。

3. DataReader:高效读取数据流

DataReader 提供快速、只进、只读的数据访问模式,占用内存小,适用于不需要缓存或随机访问的场景。

using (SqlCommand cmd = new SqlCommand("SELECT Name, Age FROM Users", conn))
using (SqlDataReader reader = cmd.ExecuteReader())
{
    while (reader.Read())
    {
        string name = reader.GetString("Name");
        int age = reader.GetInt32("Age");
        Console.WriteLine($"{name}, {age}");
    }
}

4. DataAdapter 与 DataSet:离线数据操作

DataAdapter 充当数据库与 DataSet 之间的桥梁,通过 Fill 方法将查询结果加载到 DataSet 中。DataSet 是内存中的数据容器,支持多表、关系、约束,并可在断开连接状态下进行增删改操作,最后通过 Update 方法同步回数据库。

通用数据库助手类实现

以下是一个封装了常见数据库操作的辅助类,支持事务管理、参数化查询以及动态 SQL 构建。

查看 DbHelper 实现代码
public sealed class DatabaseHelper : IDisposable
{
    private DbConnection _connection;
    private DbTransaction _transaction;
    private DbProviderFactory _factory;

    public DatabaseHelper(string connectionString, string providerName)
    {
        _factory = DbProviderFactories.GetFactory(providerName);
        _connection = _factory.CreateConnection();
        _connection.ConnectionString = connectionString;
    }

    public void OpenConnection()
    {
        if (_connection.State != ConnectionState.Open)
            _connection.Open();
    }

    public void BeginTransaction()
    {
        OpenConnection();
        _transaction = _connection.BeginTransaction();
    }

    public void Commit()
    {
        _transaction?.Commit();
        _transaction = null;
    }

    public void Rollback()
    {
        _transaction?.Rollback();
        _transaction = null;
    }

    public int ExecuteNonQuery(string sql, params DbParameter[] parameters)
    {
        using var command = CreateCommand(sql, parameters);
        return command.ExecuteNonQuery();
    }

    public object ExecuteScalar(string sql, params DbParameter[] parameters)
    {
        using var command = CreateCommand(sql, parameters);
        return command.ExecuteScalar() ?? null;
    }

    public DbDataReader ExecuteReader(string sql, params DbParameter[] parameters)
    {
        var command = CreateCommand(sql, parameters);
        return command.ExecuteReader(CommandBehavior.CloseConnection);
    }

    public DataTable ExecuteDataTable(string sql, params DbParameter[] parameters)
    {
        using var command = CreateCommand(sql, parameters);
        using var adapter = _factory.CreateDataAdapter();
        adapter.SelectCommand = command;
        var table = new DataTable();
        adapter.Fill(table);
        return table;
    }

    public DataSet ExecuteDataSet(string sql, params DbParameter[] parameters)
    {
        using var command = CreateCommand(sql, parameters);
        using var adapter = _factory.CreateDataAdapter();
        adapter.SelectCommand = command;
        var dataset = new DataSet();
        adapter.Fill(dataset);
        return dataset;
    }

    private DbCommand CreateCommand(string sql, DbParameter[] parameters)
    {
        var cmd = _connection.CreateCommand();
        cmd.CommandText = sql;
        cmd.Transaction = _transaction;
        if (parameters != null)
        {
            foreach (var param in parameters)
                cmd.Parameters.Add(param);
        }
        return cmd;
    }

    public void Dispose()
    {
        _transaction?.Dispose();
        _connection?.Dispose();
        _transaction = null;
        _connection = null;
    }
}

SQL Server 专用操作封装

针对 SQL Server 的高频操作,可进一步封装为静态工具类,简化调用流程。

查看 SqlHelper 实现代码
public static class SqlDataAccess
{
    public static string ConnectionString { get; set; }

    public static int Execute(string sql, params SqlParameter[] parameters)
    {
        using var conn = new SqlConnection(ConnectionString);
        using var cmd = new SqlCommand(sql, conn);
        if (parameters != null)
            cmd.Parameters.AddRange(parameters);
        conn.Open();
        return cmd.ExecuteNonQuery();
    }

    public static object GetScalar(string sql, params SqlParameter[] parameters)
    {
        using var conn = new SqlConnection(ConnectionString);
        using var cmd = new SqlCommand(sql, conn);
        if (parameters != null)
            cmd.Parameters.AddRange(parameters);
        conn.Open();
        var result = cmd.ExecuteScalar();
        return result == DBNull.Value ? null : result;
    }

    public static SqlDataReader Read(string sql, params SqlParameter[] parameters)
    {
        var conn = new SqlConnection(ConnectionString);
        var cmd = new SqlCommand(sql, conn);
        if (parameters != null)
            cmd.Parameters.AddRange(parameters);
        conn.Open();
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);
    }

    public static DataTable QueryTable(string sql, params SqlParameter[] parameters)
    {
        using var conn = new SqlConnection(ConnectionString);
        using var cmd = new SqlCommand(sql, conn);
        if (parameters != null)
            cmd.Parameters.AddRange(parameters);
        using var adapter = new SqlDataAdapter(cmd);
        var table = new DataTable();
        adapter.Fill(table);
        return table;
    }

    public static void ExecuteInTransaction(Dictionary<string, SqlParameter[]> sqlCommands)
    {
        using var conn = new SqlConnection(ConnectionString);
        conn.Open();
        using var trans = conn.BeginTransaction();
        try
        {
            foreach (var entry in sqlCommands)
            {
                using var cmd = new SqlCommand(entry.Key, conn, trans);
                if (entry.Value != null)
                    cmd.Parameters.AddRange(entry.Value);
                cmd.ExecuteNonQuery();
            }
            trans.Commit();
        }
        catch
        {
            trans.Rollback();
            throw;
        }
    }
}

最佳实践建议

  • 始终使用参数化查询防止 SQL 注入攻击。
  • 利用 using 语句确保连接和资源正确释放。
  • 对于大数据量读取优先考虑 DataReader;需要离线操作时使用 DataSet/DataTable。
  • 事务操作应尽量短小,避免长时间锁定资源。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。