教學課程:使用 Azure SQL Database C# 以及 ADO.NET 設計關聯式資料庫

適用于:Azure SQL資料庫

Azure SQL Database 是 Microsoft Cloud (Azure) 中的關聯式資料庫即服務 (DBaaS)。 在本教學課程裡,您將了解如何搭配使用 Visual Studio 與 Azure 入口網站和 ADO.NET 執行下列操作:

  • 使用 Azure 入口網站建立資料庫
  • 使用 Azure 入口網站設定伺服器層級的 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 入口網站左上角的 [建立資源]。

  2. 在 [新增] 頁面上,選取 [Azure Marketplace] 區段中的 [資料庫],然後按一下 [精選] 區段中的 [SQL Database]。

    建立空白資料庫

  3. 使用下列資訊填寫 SQL Database 表單,如上圖所示︰

    設定 建議的值 描述
    資料庫名稱 yourDatabase 如需有效的資料庫名稱,請參閱資料庫識別碼
    訂用帳戶 yourSubscription 如需訂用帳戶的詳細資訊,請參閱訂用帳戶
    資源群組 yourResourceGroup 如需有效的資源群組名稱,請參閱命名規則和限制
    選取來源 空白資料庫 指定應建立空白資料庫。
  4. 按一下 [伺服器] 來使用現有伺服器,或建立及設定新的伺服器。 選取現有的伺服器,或按一下 [建立新伺服器] 並且在 [新伺服器] 表單中填寫下列資訊︰

    設定 建議的值 描述
    伺服器名稱 任何全域唯一名稱 如需有效的伺服器名稱,請參閱命名規則和限制
    伺服器管理員登入 任何有效名稱 如需有效的登入名稱,請參閱資料庫識別碼
    密碼 任何有效密碼 您的密碼至少要有 8 個字元,而且必須使用下列幾種字元的其中三種︰大寫字元、小寫字元、數字和非英數字元。
    位置 任何有效位置 如需區域的相關資訊,請參閱 Azure 區域

    建立資料庫伺服器

  5. 按一下 [選取]。

  6. 按一下 [定價層] 可指定服務層、DTU 或虛擬核心的數目,以及儲存體數量。 您可以瀏覽 DTU/虛擬核心數目的選項,以及可供您每個服務層級使用的儲存體。

    在選取服務層、DTU 或 vCore 數目和儲存體數量之後,按一下 [套用]。

  7. 為空白資料庫輸入 [定序]\(在此教學課程中使用預設值)。 如需定序的詳細資訊,請參閱定序

  8. 您現在已完成 SQL Database 表單,請按一下 [建立] 來佈建資料庫。 這個步驟可能需要幾分鐘的時間。

  9. 在工具列上,按一下 [通知] 以監視部署程序。

    此螢幕擷取畫面顯示正在進行部署的 Azure 入口網站中的通知。

建立伺服器層級 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 連線到伺服器和資料庫。

    伺服器名稱

  3. 在工具列上按一下 [設定伺服器防火牆]。 伺服器的 [防火牆設定] 頁面會隨即開啟。

    伺服器層級 IP 防火牆規則

  4. 按一下工具列上的 [新增用戶端 IP],將目前的 IP 位址新增至新的 IP 防火牆規則。 IP 防火牆規則可以針對單一 IP 位址或 IP 位址範圍開啟連接埠 1433。

  5. 按一下 [檔案] 。 系統便會為目前的 IP 位址建立伺服器層級 IP 防火牆規則,以便在伺服器上開啟連接埠 1433。

  6. 依序按一下 [確定],然後關閉 [防火牆設定] 頁面。

您的 IP 位址現在可以通過 IP 防火牆。 您現在可以使用 SQL Server Management Studio 或您選擇的其他工具來連線至您的資料庫。 務必使用先前建立的伺服器管理帳戶。

重要

根據預設,已對所有 Azure 服務啟用透過 SQL Database IP 防火牆存取。 按一下此頁面上的 [關閉] 即可對所有 Azure 服務停用存取權。

C# 程式範例

本文的下一節會呈現使用 ADO.NET 將 TRANSACT-SQL (T-SQL) 陳述式傳送到 SQL Database 的 C# 程式。 C# 程式會示範下列動作:

實體關聯圖 (ERD)

CREATE TABLE 陳述式包含 REFERENCES 關鍵字,可建立兩個資料表之間的「外部索引鍵」(FK) 關聯性。 如果您使用 tempdb,請使用一對前置破折號將 --REFERENCES 關鍵字註解化。

ERD 會顯示兩個資料表之間的關聯性。 tabEmployee.DepartmentCode「子」資料行中的值受限於 tabDepartment.DepartmentCode「父」資料行中的值。

顯示外部索引鍵的 ERD

注意

您可以選擇編輯 T-SQL,將前置 # 新增至資料表名稱,以將其建立為 tempdb 中的暫存資料表。 沒有測試資料庫可供使用時,這很適合用於示範。 在外部索引鍵使用期間不會強制執行任何參考,而在程式完成執行之後,暫存資料表會在連線關閉時自動刪除。

編譯和執行

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 入口網站建立資料庫
  • 使用 Azure 入口網站設定伺服器層級的 IP 防火牆規則
  • 使用 ADO.NET 和 Visual Studio 連線到資料庫
  • 使用 ADO.NET 建立資料表
  • 使用 ADO.NET 插入、更新和刪除資料
  • 使用 ADO.NET 查詢資料

請前進到下一個教學課程,以了解資料移轉。