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

適用於:Azure SQL Database

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 查詢資料

提示

這款免費的 Learn 模組顯示如何開發和設定可查詢 Azure SQL Database 的 ASP.NET 應用程式 (包括建立簡易資料庫)。

必要條件

登入 Azure 入口網站

登入 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 連線到伺服器和資料庫。

    Screenshot of the Azure portal, database overview page, with the server name highlighted.

  3. 在 [設定] 底下,選取 [網路]。 選擇 [公用存取] 索引標籤,然後選取 [公用網路存取] 下方的 [選取的網路] 以顯示 [防火牆規則] 區段。

    Screenshot of the Azure portal, networking page, showing where to set the server-level IP firewall rule.

  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 showing foreign key

注意

您可以選擇編輯 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
}

提示

若要深入瞭解如何撰寫 SQL 查詢,請瀏覽 教學課程:撰寫 Transact-SQL 語句

後續步驟

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