在 .NET 應用程式中使用 Microsoft.Data.SqlClient

在這個快速入門中,你會建立一個 .NET 主控台應用程式:

  • 它會從環境變數讀取連線字串,而非從原始碼中讀取。
  • 非同步開啟連線。
  • 如果表格不存在,則建立該表格。
  • 插入一列帶有參數化指令的列。
  • 使用參數化查詢讀取資料列。
  • 處理 SQL 與取消錯誤。

範例中使用了 Microsoft。Data.SqlClient 7.0.3,目前的穩定版本。

Prerequisites

你需要 .NET 10 SDK 或後續支援的 .NET SDK

建立 SQL 資料庫

在以下平台建立或連接 SQL 資料庫:

快速入門會自行建立資料表,因此不需要範例資料。 資料庫識別需要具備連線,以及建立資料表、向資料表插入資料,並從資料表選取資料的權限。

在 Microsoft Fabric 的 SQL 資料庫中,從 SQL 資料庫項目複製伺服器名稱與資料庫名稱。 不要使用 SQL Analytics 端點。 該身分需要項目的讀取權限,而工作區角色或項目權限可提供此權限。 欲了解更多資訊,請參閱 SQL 資料庫中的認證。 不支援 SQL 認證。

對於 Azure SQL Database,請設定 Microsoft Entra ID 認證與資料庫存取

建立專案

執行以下命令:

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

擴充套件提供驅動程式提供的 Microsoft Entra ID 認證模式。 僅使用 Windows 整合認證或 SQL 認證的應用程式可以省略 Microsoft.Data.SqlClient.Extensions.Azure

設定連線

設定 SQL_CONNECTION_STRING 資料庫的環境變數。 不要在原始碼中放入密碼、存取權杖或正式環境的連線字串。

選擇其中一個起始點並替換佔位符。

Fabric SQL 或 Azure SQL 搭配無密碼驗證

請以 Microsoft Entra ID 中有資料庫存取權的身份登入。 本地開發時,請使用開發工具如 Azure CLI:

az login

從 Fabric 或 Azure 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 中託管且連接 Azure SQL 的應用程式,請授予其管理身份資料庫存取權,然後使用 Authentication=Active Directory Managed Identity。 關於其他 Microsoft Entra ID 選項,請參見 Microsoft Entra ID 認證

透過 TCP 的 SQL Server

使用伺服器、埠號、資料庫,並從你現有的 SQL Server 或你遵循的設定指南登入。 以下的 SQL 驗證範例是針對本地開發容器。 對於 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

若環境支援 Windows 整合認證或 Kerberos,則將 和 Password 替換User IDIntegrated Security=true。 關於設定需求,請參見 SQL Server 認證

新增應用程式代碼

請將 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;
        """;

    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);
        """;

    int insertedId;
    using (var insertCommand =
        new SqlCommand(insertSql, connection) { CommandTimeout = 30 })
    {
        insertCommand.Parameters.Add(
            new SqlParameter("@message", SqlDbType.NVarChar, 200)
            {
                Value = "Hello from Microsoft.Data.SqlClient"
            });

        object? result =
            await insertCommand.ExecuteScalarAsync(cancellation.Token);
        insertedId = Convert.ToInt32(result);
    }

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

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

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

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

    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);
    return 3;
}

參數類型與大小與資料表欄位相符。 參數會與 SQL 文字分開傳送值,防止這些值改變命令語法,並幫助 SQL Server 重用查詢計畫。

await using 即使發生例外狀況,也會釋放讀取器和連線。 釋放連線會將其實體連線歸還至連線集區,而不是讓一個連線在應用程式的整個生命週期內維持開啟狀態。

執行應用程式

執行應用程式:

dotnet run

應用程式會列印它插入的那一列:

1: Hello from Microsoft.Data.SqlClient at <timestamp>

每個資料庫的身份值與時間戳記各不相同。

如果連線失敗,則使用 SQL 錯誤號碼和錯誤輸出中的用戶端連線 ID。 檢查伺服器和資料庫名稱、網路存取、資料庫權限、認證設定和憑證設定。 不要將 TrustServerCertificate=true 新增至 Azure SQL 或生產環境連線,作為通用的連線修正方式。

在應用程式中使用該圖案

當你將範例移入 API、服務、桌面應用程式或背景工作器時,請遵守以下界限:

  • 透過應用程式的設定系統載入連接資訊。
  • 開啟一個連線來執行短暫的工作單元,然後將其釋放。
  • 在 open、command 和 reader 呼叫中傳遞 CancellationToken
  • 根據作業設定命令逾時時間。
  • 對於每個從 SQL 陳述式外部傳入的值,都應使用參數。
  • 記錄SqlException.NumberClientConnectionId,但不要記錄認證資訊或存取權杖。
  • 僅在發生暫態故障時才加入重試機制,且僅在可安全重複執行該作業時才這麼做。

下一步