자습서: Azure SQL Database C# 및 ADO.NET에서 관계형 데이터베이스 디자인

적용 대상: Azure SQL Database

Azure SQL 데이터베이스는 Microsoft Cloud(Azure)의 관계형 DBaaS(Database-As-A-Service)입니다. 이 자습서에서는 Visual Studio에서 Azure Portal 및 ADO.NET을 사용하여 다음과 같은 작업을 수행하는 방법에 대해 알아봅니다.

  • Azure Portal을 사용하여 데이터베이스 만들기
  • Azure Portal을 사용하여 서버 수준 IP 방화벽 규칙 설정
  • ADO.NET 및 Visual Studio를 사용하여 데이터베이스에 연결
  • ADO.NET을 사용하여 테이블 만들기
  • ADO.NET을 사용하여 데이터 삽입, 업데이트 및 삭제
  • ADO.NET 데이터 쿼리

*Azure 구독이 아직 없는 경우 시작하기 전에 체험 계정을 만듭니다.

다음 무료 Learn 모듈을 사용하면 간단한 데이터베이스 생성을 포함하여 Azure SQL Database를 쿼리하는 ASP.NET 애플리케이션을 개발하고 구성하는 방법을 배울 수 있습니다.

필수 구성 요소

Visual Studio 2019 이상 설치

Azure SQL Database에서 빈 데이터베이스 만들기

Azure SQL Database의 데이터베이스는 정의된 컴퓨팅 및 스토리지 리소스 세트를 사용하여 생성됩니다. 데이터베이스는 Azure 리소스 그룹 내에 생성되고 논리 SQL 서버를 사용하여 관리됩니다.

다음 단계에 따라 빈 데이터베이스를 만듭니다.

  1. Azure Portal의 왼쪽 위 모서리에서 리소스 만들기를 선택합니다.

  2. 새로 만들기 페이지의 Azure Marketplace 섹션에서 데이터베이스를 선택한 다음, 추천 섹션에서 SQL Database를 선택합니다.

    Azure Marketplace에서 SQL Database를 선택하는 Azure Portal의 스크린샷.

  3. 위의 이미지에 표시된 대로 다음과 같은 정보를 사용하여 SQL Database 형식을 작성합니다.

    설정 제안 값 Description
    데이터베이스 이름 yourDatabase 유효한 데이터베이스 이름은 데이터베이스 식별자를 참조하세요.
    구독 yourSubscription 구독에 대한 자세한 내용은 구독을 참조하세요.
    리소스 그룹 yourResourceGroup 유효한 리소스 그룹 이름은 명명 규칙 및 제한 사항을 참조하세요.
    원본 선택 빈 데이터베이스 빈 데이터베이스를 만들도록 지정합니다.
  4. 서버를 선택하여 기존 서버를 사용하거나 새 서버를 만들고 구성합니다. 기존 서버를 선택하거나 새 서버 만들기를 선택하고 새 서버 양식에 다음 정보를 입력합니다.

    설정 제안 값 Description
    서버 이름 전역적으로 고유한 이름 유효한 서버 이름은 명명 규칙 및 제한 사항을 참조하세요.
    서버 관리자 로그인 유효한 이름 유효한 로그인 이름은 데이터베이스 식별자를 참조하세요.
    암호 유효한 암호 암호는 8자 이상이어야 하며 대문자, 소문자, 숫자 및 영숫자가 아닌 문자 범주 중 세 가지 범주의 문자를 사용해야 합니다.
    위치 유효한 위치 지역에 대한 자세한 내용은 Azure 지역을 참조하세요.

    Azure용 논리 서버 배포 페이지를 보여 주는 Azure Portal의 스크린샷.

  5. 선택을 선택합니다.

  6. 가격 책정 계층을 선택하여 서비스 계층, DTU나 vCore 개수 및 스토리지 양을 지정합니다. 각 서비스 계층에 대해 사용할 수 있는 DTU/vCore 및 스토리지 수에 대한 옵션을 살펴볼 수 있습니다.

    서비스 계층, DTU 또는 vCore 수, 스토리지 양을 선택한 후 적용을 선택합니다.

  7. 빈 데이터베이스에 대한 데이터 정렬을 입력합니다(이 자습서의 경우 기본값 사용). 데이터 정렬에 대한 자세한 내용은 데이터 정렬을 참조하세요.

  8. 이제 SQL Database 양식을 완료했으므로 만들기를 선택하여 데이터베이스를 프로비전합니다. 이 단계를 완료하는 데 몇 분이 걸릴 수 있습니다.

  9. 도구 모음에서 알림을 선택하여 배포 프로세스를 모니터링합니다.

    스크린샷은 배포가 진행 중인 Azure Portal의 알림을 보여줍니다.

서버 수준 IP 방화벽 규칙 만들기

SQL Database는 서버 수준에서 IP 방화벽을 만듭니다. 방화벽 규칙에서 특정 IP가 방화벽을 통과하도록 허용하지 않는 한 이 방화벽은 외부 애플리케이션과 도구가 서버 및 서버의 데이터베이스에 연결하지 못하게 차단합니다. 데이터베이스에 대한 외부 연결을 사용하려면 먼저 IP 주소(또는 IP 주소 범위)에 대한 IP 방화벽 규칙을 추가해야 합니다. 다음 단계에 따라 서버 수준 IP 방화벽 규칙을 만듭니다.

중요

SQL Database는 포트 1433을 통해 통신합니다. 회사 네트워크 내에서 이 서비스에 연결을 시도하면 포트 1433을 통한 아웃바운드 트래픽을 네트워크 방화벽에서 허용하지 않을 수 있습니다. 이 경우 관리자가 1433 포트를 열지 않으면 데이터베이스에 연결할 수 없습니다.

  1. 배포가 완료되면 왼쪽 메뉴에서 SQL 데이터베이스를 선택한 다음, SQL 데이터베이스 페이지에서 yourDatabase를 선택합니다. 정규화된 서버 이름(예: yourserver.database.windows.net)을 표시하고 추가 구성 옵션을 제공하는 데이터베이스 개요 페이지가 열립니다.

  2. SQL Server Management Studio에서 서버 및 데이터베이스에 연결하는 데 사용할 수 있도록 이 정규화된 서버 이름을 복사합니다.

    서버 이름이 강조 표시된 Azure Portal 데이터베이스 개요 페이지의 스크린샷.

  3. 설정에서 네트워킹을 선택합니다. 공용 액세스 탭을 선택한 다음, 공용 네트워크 액세스에서 선택한 네트워크를 선택하여 방화벽 규칙 섹션을 표시합니다.

    서버 수준 IP 방화벽 규칙을 설정할 위치를 보여 주는 Azure Portal 네트워킹 페이지의 스크린샷.

  4. 도구 모음에서 클라이언트 IP 추가를 선택하여 현재 IP 주소를 새 IP 방화벽 규칙에 추가합니다. IP 방화벽 규칙은 단일 IP 주소 또는 IP 주소의 범위에 1433 포트를 열 수 있습니다.

  5. 저장을 선택합니다. 서버의 1433 포트를 여는 현재 IP 주소에 서버 수준 IP 방화벽 규칙이 생성됩니다.

  6. 확인을 선택한 다음, 방화벽 설정 페이지를 닫습니다.

이제 IP 주소가 IP 방화벽을 통과할 수 있습니다. 이제 SQL Server Management Studio 또는 원하는 다른 도구를 사용하여 데이터베이스에 연결할 수 있습니다. 이전에 만든 서버 관리자 계정을 사용해야 합니다.

중요

기본적으로 모든 Azure 서비스에는 SQL Database IP 방화벽을 통한 액세스가 사용됩니다. 이 페이지에서 끄기를 선택하여 모든 Azure 서비스에 대한 액세스를 사용하지 않도록 설정합니다.

C# 프로그램 예

이 문서의 다음 섹션에는 ADO.NET을 사용하여 T-SQL(Transact-SQL) 문을 SQL Database로 보내는 C# 프로그램이 나와 있습니다. C# 프로그램은 다음 작업을 보여줍니다.

엔터티 관계 다이어그램(ERD)

CREATE TABLE 명령문에는 두 테이블 간의 외래 키(FK) 관계를 만들기 위해 REFERENCES 키워드가 있습니다. tempdb를 사용하는 경우 선행 대시의 쌍을 사용하여 --REFERENCES 키워드를 주석으로 처리합니다.

ERD는 두 테이블 간의 관계를 표시합니다. tabEmployee.DepartmentCode자식 열의 값은 tabDepartment.DepartmentCode부모 열의 값으로 제한됩니다.

외래 키를 표시하는 ERD

참고

tempdb에서 #를 테이블 이름 앞에 추가하여 임시 테이블로 만드는 T-SQL 편집 옵션이 있습니다. 이는 사용할 수 있는 테스트 데이터베이스가 없는 경우 데모용으로 유용합니다. 외래 키에 대한 참조는 사용하는 동안 적용되지 않으며 프로그램 실행이 완료된 후 연결을 닫으면 임시 테이블은 자동으로 삭제됩니다.

컴파일 및 실행

C# 프로그램은 논리적으로 하나의 .cs 파일이며, 물리적으로 여러 코드 블록으로 분할되어 각 블록을 보다 쉽게 이해할 수 있습니다. 프로그램을 컴파일하고 실행하려면 다음 단계를 수행합니다.

  1. Visual Studio에서 C# 프로젝트를 만듭니다. 프로젝트 형식은 템플릿>Visual C#>Windows데스크톱>콘솔 앱(.NET Framework) 에 있는 콘솔이어야 합니다.

  2. 파일 Program.cs에서 다음 단계를 사용하여 코드의 시작 줄을 바꿉니다.

    1. 표시되는 동일한 순서로 다음 코드 블록을 복사 및 붙여넣기합니다. 데이터베이스에 연결, T-SQL 생성데이터베이스에 전송을 참조하세요.

    2. Main 메서드에서 다음 값을 변경합니다.

      • cb.DataSource
      • cb.UserID
      • cb.Password
      • cb.InitialCatalog
  3. System.Data.dll 어셈블리가 참조되는지 확인합니다. 확인하려면 솔루션 탐색기 창에서 참조 노드를 확장합니다.

  4. Visual Studio의 프로그램을 빌드 및 실행하려면 시작 단추를 선택합니다. 보고서 출력이 프로그램 창에 표시됩니다. GUID 값은 테스트 실행 간에 달라질 수 있습니다.

    =================================
    T-SQL to 2 - Create-Tables...
    -1 = rows affected.
    
    =================================
    T-SQL to 3 - Inserts...
    8 = rows affected.
    
    =================================
    T-SQL to 4 - Update-Join...
    2 = rows affected.
    
    =================================
    T-SQL to 5 - Delete-Join...
    2 = rows affected.
    
    =================================
    Now, SelectEmployees (6)...
    8ddeb8f5-9584-4afe-b7ef-d6bdca02bd35 , Alison , 20 , acct , Accounting
    9ce11981-e674-42f7-928b-6cc004079b03 , Barbara , 17 , hres , Human Resources
    315f5230-ec94-4edd-9b1c-dd45fbb61ee7 , Carol , 22 , acct , Accounting
    fcf4840a-8be3-43f7-a319-52304bf0f48d , Elle , 15 , NULL , NULL
    View the report output here, then press any key to end the program...
    

ADO.NET을 사용하여 SQL Database에 연결

using System;
using System.Data.SqlClient;   // System.Data.dll
//using System.Data;           // For:  SqlDbType , ParameterDirection

namespace csharp_db_test
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var cb = new SqlConnectionStringBuilder();
                cb.DataSource = "your_server.database.windows.net";
                cb.UserID = "your_user";
                cb.Password = "your_password";
                cb.InitialCatalog = "your_database";

                using (var connection = new SqlConnection(cb.ConnectionString))
                {
                    connection.Open();

                    Submit_Tsql_NonQuery(connection, "2 - Create-Tables", Build_2_Tsql_CreateTables());

                    Submit_Tsql_NonQuery(connection, "3 - Inserts", Build_3_Tsql_Inserts());

                    Submit_Tsql_NonQuery(connection, "4 - Update-Join", Build_4_Tsql_UpdateJoin(),
                        "@csharpParmDepartmentName", "Accounting");

                    Submit_Tsql_NonQuery(connection, "5 - Delete-Join", Build_5_Tsql_DeleteJoin(),
                        "@csharpParmDepartmentName", "Legal");

                    Submit_6_Tsql_SelectEmployees(connection);
                }
            }
            catch (SqlException e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.WriteLine("View the report output here, then press any key to end the program...");
            Console.ReadKey();
        }

T-SQL 명령문을 반환하는 메서드

static string Build_2_Tsql_CreateTables()
{
    return @"
        DROP TABLE IF EXISTS tabEmployee;
        DROP TABLE IF EXISTS tabDepartment;  -- Drop parent table last.

        CREATE TABLE tabDepartment
        (
            DepartmentCode  nchar(4)          not null    PRIMARY KEY,
            DepartmentName  nvarchar(128)     not null
        );

        CREATE TABLE tabEmployee
        (
            EmployeeGuid    uniqueIdentifier  not null  default NewId()    PRIMARY KEY,
            EmployeeName    nvarchar(128)     not null,
            EmployeeLevel   int               not null,
            DepartmentCode  nchar(4)              null
            REFERENCES tabDepartment (DepartmentCode)  -- (REFERENCES would be disallowed on temporary tables.)
        );
    ";
}

static string Build_3_Tsql_Inserts()
{
    return @"
        -- The company has these departments.
        INSERT INTO tabDepartment (DepartmentCode, DepartmentName)
        VALUES
            ('acct', 'Accounting'),
            ('hres', 'Human Resources'),
            ('legl', 'Legal');

        -- The company has these employees, each in one department.
        INSERT INTO tabEmployee (EmployeeName, EmployeeLevel, DepartmentCode)
        VALUES
            ('Alison'  , 19, 'acct'),
            ('Barbara' , 17, 'hres'),
            ('Carol'   , 21, 'acct'),
            ('Deborah' , 24, 'legl'),
            ('Elle'    , 15, null);
    ";
}

static string Build_4_Tsql_UpdateJoin()
{
    return @"
        DECLARE @DName1  nvarchar(128) = @csharpParmDepartmentName;  --'Accounting';

        -- Promote everyone in one department (see @parm...).
        UPDATE empl
        SET
            empl.EmployeeLevel += 1
        FROM
            tabEmployee   as empl
        INNER JOIN
            tabDepartment as dept ON dept.DepartmentCode = empl.DepartmentCode
        WHERE
            dept.DepartmentName = @DName1;
    ";
}

static string Build_5_Tsql_DeleteJoin()
{
    return @"
        DECLARE @DName2  nvarchar(128);
        SET @DName2 = @csharpParmDepartmentName;  --'Legal';

        -- Right size the Legal department.
        DELETE empl
        FROM
            tabEmployee   as empl
        INNER JOIN
            tabDepartment as dept ON dept.DepartmentCode = empl.DepartmentCode
        WHERE
            dept.DepartmentName = @DName2

        -- Disband the Legal department.
        DELETE tabDepartment
            WHERE DepartmentName = @DName2;
    ";
}

static string Build_6_Tsql_SelectEmployees()
{
    return @"
        -- Look at all the final Employees.
        SELECT
            empl.EmployeeGuid,
            empl.EmployeeName,
            empl.EmployeeLevel,
            empl.DepartmentCode,
            dept.DepartmentName
        FROM
            tabEmployee   as empl
        LEFT OUTER JOIN
            tabDepartment as dept ON dept.DepartmentCode = empl.DepartmentCode
        ORDER BY
            EmployeeName;
    ";
}

T-SQL을 데이터베이스에 제출

static void Submit_6_Tsql_SelectEmployees(SqlConnection connection)
{
    Console.WriteLine();
    Console.WriteLine("=================================");
    Console.WriteLine("Now, SelectEmployees (6)...");

    string tsql = Build_6_Tsql_SelectEmployees();

    using (var command = new SqlCommand(tsql, connection))
    {
        using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                Console.WriteLine("{0} , {1} , {2} , {3} , {4}",
                    reader.GetGuid(0),
                    reader.GetString(1),
                    reader.GetInt32(2),
                    (reader.IsDBNull(3)) ? "NULL" : reader.GetString(3),
                    (reader.IsDBNull(4)) ? "NULL" : reader.GetString(4));
            }
        }
    }
}

static void Submit_Tsql_NonQuery(
    SqlConnection connection,
    string tsqlPurpose,
    string tsqlSourceCode,
    string parameterName = null,
    string parameterValue = null
    )
{
    Console.WriteLine();
    Console.WriteLine("=================================");
    Console.WriteLine("T-SQL to {0}...", tsqlPurpose);

    using (var command = new SqlCommand(tsqlSourceCode, connection))
    {
        if (parameterName != null)
        {
            command.Parameters.AddWithValue(  // Or, use SqlParameter class.
                parameterName,
                parameterValue);
        }
        int rowsAffected = command.ExecuteNonQuery();
        Console.WriteLine(rowsAffected + " = rows affected.");
    }
}
} // EndOfClass
}

다음 단계

이 자습서에서는 데이터베이스 및 테이블 만들기, 데이터베이스에 연결, 데이터 로드 및 쿼리 실행과 같은 기본적인 데이터베이스 작업에 대해 배웠습니다. 구체적으로 다음 작업 방법을 알아보았습니다.

  • Azure Portal을 사용하여 데이터베이스 만들기
  • Azure Portal을 사용하여 서버 수준 IP 방화벽 규칙 설정
  • ADO.NET 및 Visual Studio를 사용하여 데이터베이스에 연결
  • ADO.NET을 사용하여 테이블 만들기
  • ADO.NET을 사용하여 데이터 삽입, 업데이트 및 삭제
  • ADO.NET 데이터 쿼리

데이터 마이그레이션에 대해 자세히 알아보려면 다음 자습서로 이동합니다.