【C#】DatabaseHelper类:原理与实践

DatabaseHelper类:原理与实践

在这里插入图片描述

1.DatabaseHelper代码

using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

public class DatabaseHelper
{
    // 数据库连接字符串,它包含了服务器位置、数据库名、认证信息等。
    // 原理:这是一个标准化的字符串,定义了如何找到并连接到数据库。
    private readonly string _connectionString;

    // 构造方法:必须传入一个有效的连接字符串来实例化这个类。
    // 原理:构造函数是类实例化时的初始化点,这里用来保证每个DatabaseHelper实例都有一个有效的连接字符串。
    public DatabaseHelper(string connectionString)
    {
        // 如果传入的连接字符串为空,那就抛出一个异常,提醒开发者这是不允许的。
        _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString), "数据库连接字符串不能为空!");
    }

    // 异步执行查询并返回一个DataTable。
    // 原理:异步执行允许方法调用返回到调用者而不等待任务完成,这样不会阻塞调用线程。
    public async Task<DataTable> ExecuteQueryAsync(string sql, CommandType commandType = CommandType.Text, SqlParameter[] parameters = null)
    {
        // 使用using语句确保资源被正确释放。
        // 原理:using声明会在结束时自动调用Dispose方法,确保连接对象被正确关闭,防止资源泄露。
        await using var conn = new SqlConnection(_connectionString);
        await conn.OpenAsync(); // 异步打开数据库连接。

        // 初始化SqlCommand并设置必要的属性。
        // 原理:SqlCommand对象负责把SQL指令传递给数据库执行。
        await using var cmd = new SqlCommand(sql, conn) { CommandType = commandType };
        if (parameters != null)
            cmd.Parameters.AddRange(parameters); // 添加参数以防止SQL注入。

        // SqlDataAdapter负责执行SqlCommand并填充DataTable。
        // 原理:DataAdapter充当了数据库和DataTable之间的桥梁,将数据映射进内存中的对象。
        await using var adapter = new SqlDataAdapter(cmd);
        var dataTable = new DataTable(); // 创建DataTable用于存放结果集。
        adapter.Fill(dataTable); // 填充DataTable。
        
        return dataTable; // 返回填充好的DataTable。
    }

    // 异步执行非查询SQL命令(如INSERT、UPDATE、DELETE)。
    // 原理:这类操作通常会改变数据库中的数据,但不需要返回数据。
    public async Task<int> ExecuteNonQueryAsync(string sql, CommandType commandType = CommandType.Text, SqlParameter[] parameters = null)
    {
        await using var conn = new SqlConnection(_connectionString);
        await conn.OpenAsync(); // 异步打开连接。

        // 初始化SqlCommand并设置必要的属性。
        // 原理:SqlCommand通过ExecuteNonQueryAsync执行SQL语句,返回受影响的行数,这是对数据库修改操作的确认。
        await using var cmd = new SqlCommand(sql, conn) { CommandType = commandType };
        if (parameters != null)
            cmd.Parameters.AddRange(parameters); // 添加参数以防止SQL注入。

        // 执行非查询SQL命令并返回影响的行数。
        return await cmd.ExecuteNonQueryAsync();
    }

    // 这个类可以根据需要扩展,比如添加事务处理、批量操作等高级功能。
}

2.原理讲解:

  1. 异步操作原理:通过使用asyncawait关键字,我们可以让数据库操作在一个独立的线程上进行,不会"冻结"用户界面或是阻塞当前执行的线程。这就允许用户在长时间操作(如从数据库检索大量数据)进行时继续与应用程序交互。

  2. SqlConnection原理SqlConnection对象是ADO.NET中用于与SQL Server数据库建立连接的类。当调用OpenAsync方法时,它在后台与数据库服务器建立连接,这个连接可以被用于之后的所有数据库操作。

  3. SqlCommand原理SqlCommand对象用于执行SQL语句或者存储过程,并返回结果。我们可以通过设置它的CommandType属性来定义我们要执行的是一个文本指令(SQL语句)还是一个存储过程。

  4. SqlParameter原理:参数化查询是一种防止SQL注入攻击的方法。通过使用SqlParameter,我们可以把外部输入作为参数传递给SQL命令,而不是直接拼接在SQL语句中,从而避免恶意输入可能导致的安全问题。

  5. SqlDataAdapter和DataTable原理SqlDataAdapter充当了一个中介,它执行SqlCommand并将结果集填充到DataTable对象中。DataTable是一个内存中的数据表示,可以被用于读取和操作数据。

3.使用案例

我们已经有了一个功能齐全并且注释详尽的DatabaseHelper类,现在让我们来编写一些使用案例,同时穿插一些幽默的元素和原理解释,确保既能学习到实际应用,又不会枯燥。

使用案例1:读取数据

假设你想要从数据库中读取一些用户信息,你可能会有一个像这样的SQL查询语句:“SELECT * FROM Users”。让我们用DatabaseHelper来执行它,并处理结果。

// 实例化DatabaseHelper。别忘了,连接字符串就像你家的WIFI密码,不能弄错,也不能告诉别人。
var databaseHelper = new DatabaseHelper("你的连接字符串");

// 异步查询所有用户数据,就像是网购一样,点击查询后可以继续逛其他的东西。
var dataTable = await databaseHelper.ExecuteQueryAsync("SELECT * FROM Users");

foreach (DataRow row in dataTable.Rows)
{
    // 逐行打印用户信息,就好比在叫号,准备领取大米。
    Console.WriteLine($"用户ID: {row["Id"]}, 用户名: {row["Username"]}");
}

这里的原理是,通过ExecuteQueryAsync方法,我们发送了一个SQL查询到数据库。它返回一个DataTable,这个DataTable包括了所有匹配查询条件的数据。我们用foreach循环遍历DataTable中的每一DataRow,就像数星星一样,但好在这里的星星(数据行)是有限的。

使用案例2:添加新数据

现在,假设我们要向数据库中添加一个新用户,我们的SQL语句可能是"INSERT INTO Users (Username, Password) VALUES (@Username, @Password)"。我们将使用参数化查询来处理这个操作。

// 再次实例化DatabaseHelper
var databaseHelper = new DatabaseHelper("你的连接字符串");

// 创建参数化查询的参数
SqlParameter[] parametersToAddUser = new SqlParameter[]
{
    // 我们用参数化查询来防止恶意的SQL注入,就像用锁链锁好自行车一样。
    new SqlParameter("@Username", SqlDbType.VarChar) { Value = "新用户"},
    new SqlParameter("@Password", SqlDbType.VarChar) { Value = "超安全的密码123"}
};

// 异步执行SQL命令,添加新用户到数据库中,就像是网上提交订单。
int rowsAffected = await databaseHelper.ExecuteNonQueryAsync(
    "INSERT INTO Users (Username, Password) VALUES (@Username, @Password)",
    CommandType.Text, parametersToAddUser);

Console.WriteLine($"插入了 {rowsAffected} 行数据。"); // 告诉我们有多少数据被成功插入,就像是确认收货一样。

在这个案例中,我们使用了参数化查询,这是因为我们不想让任何坏蛋通过SQL注入来破坏我们的数据库,就像是我们不会让陌生人随意进入我们的房间。通过定义SqlParameter数组,并将其传递给ExecuteNonQueryAsync方法,我们确保了我们的SQL命令既安全又容易理解。

使用案例3:更新数据

让我们来更新一个用户的密码。在现实生活中,这可能是因为用户忘记了密码,但在我们的例子中,这只是因为我们想展示一下这个工具类的魅力。

// 你懂的,每次操作前都得实例化DatabaseHelper
var databaseHelper = new DatabaseHelper("你的连接字符串");

// 参数化查询参数,为了用户的账户安全
SqlParameter[] parametersToUpdatePassword = new SqlParameter[]
{
    new SqlParameter("@UserId", SqlDbType.Int) { Value = 1 },
    new SqlParameter("@NewPassword", SqlDbType.VarChar) { Value = "新的超安全的密码456"}
};

// 异步更新用户密码
int rowsAffected = await databaseHelper.ExecuteNonQueryAsync(
    "UPDATE Users SET Password = @NewPassword WHERE Id = @UserId",
    CommandType.Text, parametersToUpdatePassword);

Console.WriteLine($"更新了 {rowsAffected} 行数据。"); // 就像是告诉用户他的密码已经被成功地重置。
注:实际使用请将connectionString放到配置文件中
  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值