1. 引言:为什么需要掌握原生数据库操作?

在日常开发中,我们经常需要与数据库打交道。虽然现在流行各种ORM框架(比如Entity Framework),但掌握原生ADO.NET操作就像厨师熟悉刀工一样重要。当你需要处理大批量数据、优化性能或维护遗留系统时,System.Data.SqlClient这个"老伙计"依然是最可靠的选择。

2. 环境准备与基础操作

2.1 项目配置

确保在.csproj文件中包含以下NuGet包引用:

<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />

2.2 基础插入示例

using System.Data.SqlClient;

public class BasicInsertExample
{
    public void InsertUser(string userName, string email)
    {
        // 连接字符串配置(实际项目建议使用配置管理)
        string connectionString = "Server=.;Database=TestDB;Integrated Security=True;";
        
        // 使用using确保资源释放
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            // 构造插入语句
            string sql = "INSERT INTO Users (UserName, Email) VALUES (@UserName, @Email)";
            
            // 创建命令对象
            using (SqlCommand command = new SqlCommand(sql, connection))
            {
                // 添加参数化查询参数
                command.Parameters.AddWithValue("@UserName", userName);
                command.Parameters.AddWithValue("@Email", email);
                
                // 打开连接
                connection.Open();
                
                // 执行非查询操作
                int rowsAffected = command.ExecuteNonQuery();
                Console.WriteLine($"成功插入{rowsAffected}条记录");
            }
        }
    }
}

3. 进阶操作技巧

3.1 批量插入优化

public void BulkInsertUsers(List<User> users)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        
        // 使用事务确保批量操作原子性
        using (SqlTransaction transaction = connection.BeginTransaction())
        {
            try
            {
                foreach (var user in users)
                {
                    using (SqlCommand command = new SqlCommand(
                        "INSERT INTO Users (UserName, Email) VALUES (@u, @e)", 
                        connection, 
                        transaction))
                    {
                        command.Parameters.AddWithValue("@u", user.Name);
                        command.Parameters.AddWithValue("@e", user.Email);
                        command.ExecuteNonQuery();
                    }
                }
                transaction.Commit();
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }
    }
}

3.2 获取插入后的自增ID

public int InsertWithReturnId(string userName)
{
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        string sql = @"INSERT INTO Users (UserName) 
                      OUTPUT INSERTED.UserId
                      VALUES (@name)";
        
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Parameters.AddWithValue("@name", userName);
        
        conn.Open();
        return (int)cmd.ExecuteScalar();
    }
}

4. 关联技术:与Entity Framework的配合

4.1 混合使用场景

// 在EF Core中执行原生SQL
context.Database.ExecuteSqlRaw(
    "INSERT INTO AuditLogs (Action, Timestamp) VALUES ({0}, {1})", 
    "UserCreated", 
    DateTime.Now);

5. 应用场景分析

  • 数据采集系统:需要高频次写入传感器数据
  • 业务系统初始化:创建基础数据时对性能有要求
  • 日志记录系统:需要保证写入成功率的同时不影响主业务

6. 技术优缺点对比

优点

  • 直接操作底层协议,性能最优
  • 完全掌控SQL执行细节
  • 适合复杂事务处理

缺点

  • 需要手动处理连接池和资源释放
  • SQL注入防护依赖开发人员自觉
  • 数据类型转换需要手动处理

7. 关键注意事项

  1. 防注入原则:永远使用参数化查询
  2. 连接管理:最大连接数建议配置为(核心数*2)+1
  3. 超时设置:根据业务需求设置合理的CommandTimeout
  4. 错误处理:建议实现重试机制(特别是网络不稳定的环境)

8. 性能优化技巧

  • 批量操作时使用SqlBulkCopy
  • 合理设置Packet Size(默认4096字节)
  • 启用MultipleActiveResultSets(MARS)特性
  • 使用异步API(ExecuteNonQueryAsync)

9. 完整实战示例

public class AdvancedDataInserter
{
    private readonly string _connString;
    
    public AdvancedDataInserter(string connectionString)
    {
        _connString = connectionString;
    }

    public async Task<int> SafeInsertAsync(UserData data)
    {
        using (var conn = new SqlConnection(_connString))
        {
            await conn.OpenAsync();
            
            var command = conn.CreateCommand();
            command.CommandText = @"
                BEGIN TRY
                    BEGIN TRANSACTION
                    
                    INSERT INTO Users (...) VALUES (...);
                    INSERT INTO Profiles (...) VALUES (...);
                    
                    COMMIT TRANSACTION
                    RETURN 1
                END TRY
                BEGIN CATCH
                    ROLLBACK TRANSACTION
                    THROW
                END CATCH";
            
            // 添加参数省略...
            
            return await command.ExecuteNonQueryAsync();
        }
    }
}

10. 总结与展望

通过本文的讲解,我们不仅掌握了使用System.Data.SqlClient进行数据插入的基础和进阶技巧,还了解了如何在不同场景下做出技术选型。虽然现代开发中ORM框架越来越普及,但在处理复杂事务、性能敏感场景时,直接使用ADO.NET仍然是不可替代的解决方案。