快速入门:使用 Microsoft.Data.SqlClient 连接并查询

在这个快速入门中,你将使用 Microsoft.Data.SqlClient 7.1.1 构建一个 .NET 控制台应用。

你从一个空文件夹、.NET SDK和一个可以从电脑访问的SQL Server或Azure SQL数据库开始。 最后用一个控制台应用创建表,插入带参数的两行,然后读取它们。

在这个过程中,应用:

  • 它从环境变量中读取 连接字符串,而不是从源代码中读取。
  • 异步开启连接。
  • 它为发送到数据库的每个值使用参数。
  • 处理 SQL 错误和取消操作。

要将相同的数据访问构建到 Web API 中,请参见快速入门:在 ASP.NET Core 应用中使用 Microsoft.Data.SqlClient。 它使用了同一张表格。

先决条件

  • .NET 10 SDK 或更高版本且受支持的 .NET SDK。 该SDK可在Windows、Linux和macOS上运行。 SDK 还构建了 .NET Framework 版本的示例,该版本仅支持 Windows,且需要 .NET Framework 4.8.1。 新开发时使用.NET版本。
  • 一个代码编辑器。 你可以使用Visual Studio、Visual Studio Code或任何编辑器配合.NET CLI。 本文使用 .NET CLI。
  • 一个你可以连接的数据库。 如果你还没有,请通过以下选项创建一个。

创建 SQL 数据库

在以下平台之一创建或连接SQL数据库:

数据库权限

应用会创建自己的表格,所以你不需要样本数据。 数据库身份需要具备连接权限,以及创建表、向表中插入数据和从表中查询数据的权限。

对于 Microsoft Fabric 中的 SQL 数据库,从 SQL 数据库项中复制服务器名和数据库名称。 不要用SQL分析端点。 该标识需要项目读取权限,而工作区角色或项目权限均可授予该权限。 更多信息请参见 SQL数据库中的认证。 不支持SQL认证。

对于 Azure SQL 数据库,配置 Microsoft Entra ID 认证和数据库访问。

创建项目

在一个空文件夹中,执行以下命令:

dotnet new console --framework net10.0 --name SqlClientQuickstart
cd SqlClientQuickstart
dotnet add package Microsoft.Data.SqlClient --version 7.1.1
dotnet add package Microsoft.Data.SqlClient.Extensions.Azure --version 7.1.1

扩展包提供驱动程序的 Microsoft Entra 认证模式,例如 Active Directory Default。 如果你的应用只使用 SQL 认证或 Windows 集成认证,可以省略 Microsoft.Data.SqlClient.Extensions.Azure。 使用两个软件包时,保持它们的版本相同。 有关其他安装选项,请参见安装、更新和部署 Microsoft.Data.SqlClient。

配置连接

为你的数据库设置 SQL_CONNECTION_STRING 环境变量。 不要在源代码中写入密码、访问令牌或生产环境连接字符串。

选择这些起始点之一并替换占位符。

使用 Microsoft Entra ID 的 Azure SQL 或 Fabric 中的 SQL 数据库

使用拥有数据库访问权限的 Microsoft Entra 身份登录。 本地开发时,可以使用开发者工具,如 Azure CLI:

az login

从Azure SQL数据库或Fabric中的SQL数据库项复制准确的服务器和数据库名称。 对于 PowerShell:

$env:SQL_CONNECTION_STRING = 'Server=tcp:<server>,1433;Database=<database>;Authentication=Active Directory Default;Encrypt=Strict;MultiSubnetFailover=true;Connect Timeout=30'

对于 Bash:

export SQL_CONNECTION_STRING='Server=tcp:<server>,1433;Database=<database>;Authentication=Active Directory Default;Encrypt=Strict;MultiSubnetFailover=true;Connect Timeout=30'

对于托管在 Azure 中的应用,授予其托管身份数据库访问权限,然后使用 Authentication=Active Directory Managed Identity。 有关其他选项,请参见 使用 Microsoft.Data.SqlClient 的 Microsoft Entra 身份验证。

SQL Server 与 SQL 认证

使用适用于你的 SQL Server 实例的服务器、端口、数据库和登录信息。 以下示例是一个没有受信任证书的本地开发实例。 对于 PowerShell:

$env:SQL_CONNECTION_STRING = 'Server=tcp:<server>,1433;Database=<database>;User ID=<user-id>;Password=<password>;Encrypt=true;TrustServerCertificate=true;Connect Timeout=30'

对于 Bash:

export SQL_CONNECTION_STRING='Server=tcp:<server>,1433;Database=<database>;User ID=<user-id>;Password=<password>;Encrypt=true;TrustServerCertificate=true;Connect Timeout=30'

Caution

TrustServerCertificate=true 跳过服务器证书验证。 只在没有受信任证书的本地开发实例中使用。 对于共享或生产型 SQL Server 实例,安装客户端信任的证书,使用该证书上的服务器名称,然后移除 TrustServerCertificate=true。 有关详细信息,请参阅 Microsoft.Data.SqlClient 中的加密和证书验证。

如果你的环境支持 Windows 集成认证或 Kerberos,请将 User ID 和 Password 替换为 Integrated Security=true。 关于设置要求,请参见 SQL Server 和 Windows 身份验证。

添加代码

用以下代码替换 Program.cs 的内容:

using System.Data;
using Microsoft.Data.SqlClient;

string? connectionString =
    Environment.GetEnvironmentVariable("SQL_CONNECTION_STRING");

if (string.IsNullOrWhiteSpace(connectionString))
{
    Console.Error.WriteLine(
        "Set the SQL_CONNECTION_STRING environment variable.");
    return 1;
}

using var cancellation = new CancellationTokenSource();
Console.CancelKeyPress += (_, eventArgs) =>
{
    eventArgs.Cancel = true;
    cancellation.Cancel();
};

try
{
    await using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync(cancellation.Token);

    const string createTableSql = """
        IF OBJECT_ID(N'dbo.SqlClientQuickstart', N'U') IS NULL
        BEGIN
            CREATE TABLE dbo.SqlClientQuickstart
            (
                Id int IDENTITY(1, 1) PRIMARY KEY,
                Message nvarchar(200) NOT NULL,
                CreatedAt datetimeoffset NOT NULL
                    CONSTRAINT DF_SqlClientQuickstart_CreatedAt
                    DEFAULT sysdatetimeoffset()
            );
        END;
        """;

    await using (var createCommand =
        new SqlCommand(createTableSql, connection) { CommandTimeout = 30 })
    {
        await createCommand.ExecuteNonQueryAsync(cancellation.Token);
    }

    const string insertSql = """
        INSERT INTO dbo.SqlClientQuickstart (Message)
        OUTPUT INSERTED.Id
        VALUES (@message);
        """;

    string[] messages =
    [
        "Hello from Microsoft.Data.SqlClient",
        "Parameters keep values out of the SQL text"
    ];

    int firstId = 0;
    await using (var insertCommand =
        new SqlCommand(insertSql, connection) { CommandTimeout = 30 })
    {
        SqlParameter messageParameter =
            insertCommand.Parameters.Add("@message", SqlDbType.NVarChar, 200);

        foreach (string message in messages)
        {
            messageParameter.Value = message;
            int id = (int)(await insertCommand.ExecuteScalarAsync(
                cancellation.Token))!;
            Console.WriteLine($"Inserted row {id}.");
            firstId = firstId == 0 ? id : firstId;
        }
    }

    const string querySql = """
        SELECT Id, Message, CreatedAt
        FROM dbo.SqlClientQuickstart
        WHERE Id >= @firstId
        ORDER BY Id;
        """;

    await using var queryCommand =
        new SqlCommand(querySql, connection) { CommandTimeout = 30 };
    queryCommand.Parameters.Add("@firstId", SqlDbType.Int).Value = firstId;

    await using SqlDataReader reader =
        await queryCommand.ExecuteReaderAsync(cancellation.Token);

    while (await reader.ReadAsync(cancellation.Token))
    {
        Console.WriteLine(
            $"{reader.GetInt32(0)}: {reader.GetString(1)} " +
            $"(created {reader.GetDateTimeOffset(2):u})");
    }

    return 0;
}
catch (OperationCanceledException)
{
    Console.Error.WriteLine("The operation was canceled.");
    return 2;
}
catch (SqlException ex)
{
    Console.Error.WriteLine(
        $"SQL error {ex.Number}, connection {ex.ClientConnectionId}: " +
        ex.Message);
    if (ex.InnerException is not null)
    {
        Console.Error.WriteLine(ex.InnerException.Message);
    }
    return 3;
}

运行应用

运行应用:

dotnet run

第一次运行应用时,表是空的,输出如下:

Inserted row 1.
Inserted row 2.
1: Hello from Microsoft.Data.SqlClient (created 2026-10-20 20:56:10Z)
2: Parameters keep values out of the SQL text (created 2026-10-20 20:56:10Z)

你的时间戳不同。 每次后续运行都会增加两行,因此ID从上一次运行中延续。

如果应用无法连接,它会打印 SQL 错误号、客户端连接 ID、错误信息和内部异常信息,然后以退出代码 3 退出。 常见问题请参见 故障排除。

代码的工作原理

  • OpenAsync、ReadAsync、CancellationToken、ExecuteReaderAsync和ExecuteScalarAsync都获得相同的ExecuteNonQueryAsync。 按 Ctrl+C 取消当前操作。
  • 插入命令只创建一次,对每条消息运行一次。 只有参数值会变。
  • 参数类型和大小与表列相匹配。 参数值会与 SQL 文本分开发送,防止这些值更改命令,并帮助 SQL Server 重用查询计划。
  • OUTPUT INSERTED.Id 返回新的标识值,因此 ExecuteScalarAsync 返回该 ID,无需再次查询。
  • await using 即使出现异常,也会释放命令、读取器和连接。 释放连接后,它会被返回连接池。 .NET Framework 版本使用 using 块,因为这些类型在 .NET Framework 上未实现 IAsyncDisposable。
  • SqlException.Number 它能识别错误,并 ClientConnectionId 使客户端故障与服务器端日志相匹配。 对于 Linux 和 macOS 上的连接失败,原因通常仅显示在 InnerException 中,例如隐藏在通用 error: 35 - An internal exception was caught 后面的证书验证失败。

Troubleshoot

错误或症状 需要检查的事项 更多信息
The certificate chain was issued by an authority that is not trusted在Windows上。 在 Linux 和 macOS 上,error: 35 - An internal exception was caught后跟内部异常Certificate failed chain validation,并带有UntrustedRoot。 服务器证书不被客户端信任,或者连接字符串中的服务器名称与证书不匹配。 安装受信任的证书。 仅可与本地开发实例配合使用 TrustServerCertificate=true Microsoft.Data.SqlClient 中的加密和证书验证
SQL error 18456 与 Login failed for user 用户名、密码或数据库名称有误,或者登录用户没有数据库访问权限。 对于 Microsoft Entra ID,检查该身份是否被添加为数据库用户。 SqlClient 故障排除指南
A network-related or instance-specific error occurred 使用 error: 26、error: 40或The wait operation timed out。 在 Linux 和 macOS 上,超时显示 SQL error 258 为 error: 35,后面是内部例外 The connection attempt timed out。 服务器名称或端口错误,服务器不接受远程TCP连接,或者防火墙封锁了端口。 对于Azure SQL,请检查服务器防火墙规则。 SqlClient 故障排除指南
System.ArgumentException: Cannot find an authentication provider for 'ActiveDirectoryDefault' 连接字符串 使用Active Directory认证模式,但项目不引用 Microsoft.Data.SqlClient.Extensions.Azure。 将与 Microsoft.Data.SqlClient 版本相同的软件包添加进来 Microsoft Entra 认证在 7.0 版本中迁移到扩展包
CS0234: The type or namespace name 'Data' does not exist in the namespace 'Microsoft' 项目未引用该 Microsoft.Data.SqlClient 软件包。 从包含项目文件的文件夹里执行 dotnet add package 命令。 安装、更新并部署 Microsoft。Data.SqlClient
恢复某个传递包的报告 NU1902 或 NU1903 驱动程序依赖的软件包已发布公告。 当报告已知漏洞的包时的操作

清理资源

应用退出后,表格会留在你的数据库中。 如果你不打算继续使用相同表的 ASP.NET Core 快速入门,可以用任意查询工具删除该表:

DROP TABLE IF EXISTS dbo.SqlClientQuickstart;

然后删除项目文件夹。 在父文件夹中,使用 PowerShell:

Remove-Item -Recurse -Force SqlClientQuickstart

对于 Bash:

rm -rf SqlClientQuickstart

清除环境变量,这样连接字符串就不会留在你的shell会话里。 对于PowerShell,运行 Remove-Item Env:\SQL_CONNECTION_STRING. 对于 Bash,运行 unset SQL_CONNECTION_STRING。

在应用中使用该图案

当你将样本迁移到API、服务、桌面应用或后台工作工具时,请遵守以下界限:

  • 通过应用的配置系统加载连接信息。
  • 打开一个连接来完成一小段工作,然后将其释放。
  • 通过 open、command 和 reader 调用传递 CancellationToken。
  • 根据具体操作设置命令超时时间。
  • 为来自SQL语句外的每个值使用参数。
  • 记录SqlException.Number和ClientConnectionId,且不记录凭证或访问令牌。
  • 仅针对瞬时性故障实施重试,并且仅当重复执行该操作是安全的时才这样做。

后续步骤