퀵스타트: Microsoft.Data.SqlClient를 사용하여 연결하고 쿼리하기

이 퀵스타트에서는 Microsoft.Data.SqlClient 7.1.1을 사용하여 .NET 콘솔 앱을 빌드합니다.

빈 폴더, .NET SDK, 그리고 컴퓨터에서 접근할 수 있는 SQL Server나 Azure SQL 데이터베이스로 시작합니다. 결과적으로 테이블을 만들고 매개변수로 두 행을 삽입한 뒤 다시 읽는 콘솔 앱이 완성됩니다.

그 과정에서 앱은 다음을 수행합니다:

  • 소스 코드 대신 환경 변수에서 연결 문자열을 읽습니다.
  • 비동기식으로 연결을 엽니다.
  • 데이터베이스에 보내는 모든 값에 대해 매개변수를 사용합니다.
  • SQL 오류 및 취소를 처리합니다

동일한 데이터 액세스를 웹 API에 구축하려면 Quickstart: ASP.NET Core 앱에서 Microsoft.Data.SqlClient 사용을 참조하세요. 같은 표를 사용합니다.

사전 요구 사항

  • .NET 10 SDK 또는 이후 지원되는 .NET SDK입니다. SDK는 Windows, Linux, macOS에서 실행됩니다. SDK는 또한 Windows에서만 실행되고 .NET Framework 4.8.1이 필요한 .NET Framework 버전을 빌드합니다. 새로운 개발에는 .NET 버전을 사용하세요.
  • 코드 에디터. Visual Studio, Visual Studio Code 또는 .NET CLI와 함께 모든 편집기를 사용할 수 있습니다. 이 문서는 .NET CLI를 사용합니다.
  • 연결할 수 있는 데이터베이스. 만약 없다면, 다음 옵션을 사용해 하나를 생성하세요.

SQL 데이터베이스 만들기

다음 플랫폼 중 하나에서 SQL 데이터베이스를 생성하거나 연결하세요:

데이터베이스 사용 권한

앱은 자체 테이블을 생성하므로 샘플 데이터가 필요하지 않습니다. 데이터베이스 정체성은 연결하고 테이블을 생성, 삽입, 선택하려면 권한이 필요합니다.

Microsoft Fabric의 SQL 데이터베이스 경우, SQL 데이터베이스 항목에서 서버와 데이터베이스 이름을 복사하세요. SQL 분석 엔드포인트는 사용하지 마세요. 아이덴티티에는 항목 읽기 권한이 필요하며, 이 권한은 워크스페이스 역할 또는 항목 권한으로 부여할 수 있습니다. 자세한 내용은 SQL 데이터베이스의 인증(Authentication)을 참조하세요. 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.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 설정하세요. 소스 코드에 비밀번호, 액세스 토큰 또는 프로덕션 연결 문자열을 넣지 마세요.

이 시작 지점 중 하나를 선택하고 자리 표시자를 교체하세요.

Azure SQL 또는 Fabric의 SQL 데이터베이스(이하) Microsoft Entra ID

데이터베이스에 접근할 수 있는 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에 호스팅된 앱의 경우, 관리형 ID에 데이터베이스 액세스 권한을 부여한 후 Authentication=Active Directory Managed Identity을 사용하세요. 다른 옵션에 대해서는 Microsoft.Data.SqlClient를 사용한 Microsoft Entra 인증을(를) 참조하세요.

SQL 인증이 있는 SQL Server

서버, 포트, 데이터베이스, 로그인 정보를 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를 지원한다면, Password와 Integrated Security=true를 User ID로 대체하세요. 설정 요구사항은 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가 마지막 실행의 ID부터 이어집니다.

앱은 연결이 안 되면 SQL 오류 번호, 클라이언트 연결 ID, 오류 메시지, 내부 예외 메시지를 출력한 후 코드 3으로 종료됩니다. 일반적인 오류에 대해서는 문제 해결을 참조하세요.

코드 작동 방식

  • OpenAsync, ExecuteNonQueryAsync, ExecuteScalarAsync, ExecuteReaderAsync, 그리고 ReadAsync 모두 동일한 CancellationToken값을 받습니다. 진행 중인 작업을 취소하려면 Ctrl+C를 누르세요.
  • insert 명령은 한 번 생성되어 각 메시지마다 한 번씩 실행됩니다. 파라미터 값만 바뀝니다.
  • 매개변수 유형과 크기는 테이블 열과 일치합니다. 매개변수는 SQL 텍스트와 별도로 값을 전송하여, 해당 값들이 명령어를 변경하지 않도록 방지하고 SQL Server가 쿼리 계획을 재사용할 수 있도록 돕습니다.
  • OUTPUT INSERTED.Id는 새 ID 값을 반환하므로 ExecuteScalarAsync는 두 번째 쿼리 없이 ID를 반환합니다.
  • await using 명령, 리더 및 연결을 해제하며, 예외가 발생하더라도 이를 해제합니다. 연결을 폐기하면 연결 풀로 다시 돌아갑니다. .NET Framework 버전은 using 블록을 사용하는데, 이는 이러한 형식이 .NET Framework에서 IAsyncDisposable을 구현하지 않기 때문입니다.
  • SqlException.Number 오류를 식별하고, ClientConnectionId 클라이언트 실패를 서버 측 로그와 대조할 수 있게 해줍니다. 리눅스와 macOS에서 연결 실패의 원인은 보통 error: 35 - An internal exception was caught에서만 확인할 수 있으며, 예를 들어 일반적인 InnerException 뒤에 있는 인증서 검증 실패와 같은 경우가 있습니다.

Troubleshoot

오류 또는 증상 확인할 사항 자세한 내용
The certificate chain was issued by an authority that is not trusted Windows에서. Linux 및 macOS에서는 error: 35 - An internal exception was caught 뒤에 UntrustedRoot가 있는 내부 예외 Certificate failed chain validation이 옵니다. 서버 인증서가 클라이언트에게 신뢰되지 않거나, 연결 문자열의 서버 이름이 인증서와 일치하지 않습니다. 신뢰할 수 있는 인증서를 설치하세요. 로컬 개발 인스턴스에서만 사용 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. 리눅스와 macOS에서는 타임아웃에 error: 35와 함께 SQL error 258가 표시되며, 그 뒤에 내부 예외 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

환경 변수를 지워서 연결 문자열이 셸 세션에 남지 않도록 하세요. PowerShell의 경우 Remove-Item Env:\SQL_CONNECTION_STRING를 실행하세요. Bash에서는 unset SQL_CONNECTION_STRING를 실행하세요.

애플리케이션에서 패턴 사용

샘플을 API, 서비스, 데스크톱 앱, 백그라운드 워커로 옮길 때 다음과 같은 경계를 유지하세요:

  • 앱 설정 시스템을 통해 연결 정보를 불러옵니다.
  • 짧은 작업 단위를 위해 한 연결을 열고, 그 후 폐기하세요.
  • open, command 및 reader 호출에 CancellationToken를 전달하세요.
  • 명령 타임아웃을 운영에 따라 설정하세요.
  • SQL 문장 외부에서 오는 모든 값에 대해 매개변수를 사용하세요.
  • 자격 증명이나 액세스 토큰은 기록하지 않고 SqlException.Number 및 ClientConnectionId를 기록하세요.
  • 재시도는 일시적인 오류에 대해서만 추가하고, 작업을 반복해도 안전한 경우에만 사용하세요.

다음 단계