Note
類別 DataSet 和相關類別是 2000 年代初的舊版 .NET Framework 技術,可讓應用程式在應用程式與資料庫中斷連線時使用記憶體中的數據。 這些技術特別適用於可讓使用者修改數據並將變更保存回資料庫的應用程式。 雖然數據集是經過證實的成功技術,但新 .NET 應用程式的建議方法是使用 Entity Framework Core。 Entity Framework 提供更自然的方式,以表格式數據作為物件模型使用,而且具有更簡單的程序設計介面。
當您建立作資料庫中數據的應用程式時,通常會執行定義連接字串、插入數據和執行預存程式等工作。 依照本文的指引,您能夠了解如何在 資料覆蓋窗體(FOD)Windows Forms 應用程式中,使用 Visual C# 或 Visual Basic 以及 ADO.NET 與資料庫互動。 所有 .NET 數據技術,包括數據集、LINQ(Language-Integrated 查詢)至 SQL 和 Entity Framework,最終都會執行與本文所示步驟類似的步驟。
本文示範如何快速將數據從資料庫取出。 如果您的應用程式需要以非嘗試方式修改數據並更新資料庫,請考慮使用 Entity Framework 和數據系結。 這麼做可讓您的使用者介面控件自動同步處理基礎數據中的變更。
若要存取本教學課程的完整程序代碼,請參閱適用於 C# 和 Visual Basic 的 Visual Studio 檔 GitHub 存放庫。
Important
為了保持程式碼的簡潔,該程式未包含適用於生產環境的例外處理。
Prerequisites
已安裝具有.NET 桌面開發和資料存儲和處理工作負載的 Visual Studio。 若要安裝它們,請開啟 Visual Studio 安裝程式,然後選擇您要修改之 Visual Studio 版本旁的 [修改 ]。
SQL Server Express LocalDB。 如果您沒有 SQL Server Express LocalDB,您可以從 SQL Server 下載頁面加以安裝。
本文假設您已熟悉 Visual Studio IDE 的基本功能。 它也假設您可以建立 Windows Forms 應用程式、將表單新增至專案、將按鈕和其他控件新增至表單、設定控件屬性和程式碼簡單事件。 如果您不熟悉這些工作,請先完成使用 C# 在 Visual Studio 中建立 Windows Forms 應用程式 教學課程,或在 Visual Studio 中使用 Visual Basic 建立 Windows Forms 應用程式 教學課程,再開始本逐步解說。
設定範例資料庫
依照下列步驟建立範例資料庫:
在 Visual Studio 中,開啟 [伺服器總管] 視窗。
以滑鼠右鍵按兩下 [資料連線 ],然後選擇 [ 建立新的 SQL Server 資料庫]。
針對 [伺服器名稱],輸入 (localdb)\mssqllocaldb。
針對 [新增資料庫名稱],輸入 Sales,然後選擇 [ 確定]。
Visual Studio 會在 [伺服器總管] 的 [數據連線] 節點下建立空的 Sales 資料庫。
以滑鼠右鍵按兩下 [銷售 數據連線],然後選取 [ 新增查詢]。
查詢編輯器視窗隨即開啟。
將 Sales Transact-SQL 文稿 複製到剪貼簿。
將 T-SQL 文稿貼到查詢編輯器視窗中,然後選取 [ 執行]。
在短時間內,查詢會完成執行,並建立資料庫物件。 資料庫包含兩個數據表:客戶和訂單。 這些數據表一開始不包含任何數據,但您可以在執行您所建立的應用程式時新增數據。 資料庫也包含五個基本預存程式。
建立表單並新增控件
使用 Windows Forms 應用程式 (.NET Framework) 範本建立 C# 或 Visual Basic 專案,並將其命名為 SimpleDataApp。
Visual Studio 會建立專案和數個檔案,包括名為 Form1 的空白 Windows 窗體。
在 [方案總管] 中,將兩個 Windows 窗體新增至您的專案,使其總共有三個窗體,並提供下列名稱:
Navigation
NewCustomer
FillOrCancel
針對每個表單,新增下列圖例所示的文字框、按鈕和其他控件。 針對每個控件,設定數據表描述的屬性。
Note
群組方塊和標籤控件能增加清晰度,但並未在程式碼中使用。
瀏覽表單
導覽表單的控制件
控件文字 控制件類型 控件屬性 新增帳戶 Button Name = btnGoToAdd 填滿或取消訂單 Button Name = btnGoToFillOrCancel Exit Button Name = btnExit NewCustomer 表單
新客戶表單的控制項
標籤/控件文字 控制件類型 控件屬性 客戶名稱 TextBox Name = txtCustomerName 客戶識別碼 TextBox Name = txtCustomerID
ReadOnly(唯讀)= True(真)建立帳戶 Button Name = btnCreateAccount 訂單金額 NumericUpdown 名稱 = numOrderAmount
DecimalPlaces = 0
最大值 = 5000訂單日期 DateTimePicker Name = dtpOrderDate
格式=短下單 Button Name = btnPlaceOrder Finish Button Name = btnAddFinish 新增另一個帳戶 Button Name = btnAddAnotherAccount FillOrCancel 表單
FillOrCancel 表單的控制項
標籤/控件文字 控制件類型 控件屬性 訂單識別碼 TextBox Name = txtOrderID 尋找訂單 Button Name = btnFindByOrderID 如果填寫訂單... DateTimePicker Name = dtpFillDate
格式=短(None) DataGridView Name = dgvCustomerOrders
ReadOnly(唯讀)= True(真)
RowHeadersVisible = False取消訂單 Button Name = btnCancelOrder 填滿順序 Button Name = btnFillOrder Finish Button Name = btnFinishUpdates
儲存連接字串
當您的應用程式嘗試開啟資料庫的連線時,您的應用程式必須具有連接字串的存取權。 若要避免需要在每個窗體上手動輸入字串,請將字串儲存在專案中 App.config 檔案中。 然後,建立方法,在從應用程式中的任何窗體呼叫 方法時,傳回字元串。
若要尋找連接字串:
在 [伺服器總管] 中,右鍵單擊 [銷售] 數據連線,然後選擇 [屬性]。
找出 [連接字串 ] 屬性,並將其字串值複製到剪貼簿。
若要將連接字串儲存在您的項目中:
在 [方案總管] 中,根據您的項目類型執行下列步驟之一:
針對 C# 專案,展開專案底下的 [屬性] 節點,然後開啟 Settings.settings 檔案。
針對 Visual Basic 專案,選取 [ 顯示所有檔案],展開 [我的專案 ] 節點,然後開啟 Settings.settings 檔案。
在 [ 名稱] 數據行中,輸入 connString。
在 [類型] 清單中,選取 [連接字串]。
在 [ 範圍] 清單中,選取 [ 應用程式]。
在 [ 值] 資料行中,輸入您的連接字串(不含任何外部引號),然後儲存變更。
Caution
在實際的應用程式中,您應該安全地儲存連接字串,如 連接字串和組態檔中所述,。 為了獲得最佳安全性,請使用不依賴將密碼儲存在連接字串中的驗證方法。 例如,內部部署 SQL Server 資料庫的 Windows 驗證。 如需詳細資訊,請參閱 儲存和編輯連接字串。
撰寫表單的程序代碼
本節包含每個表單功能的簡短概觀。 它也會提供在表單上選取按鈕時定義基礎邏輯的程序代碼。
導航表單
當您執行應用程式並包含下列按鈕時,導覽表單隨即開啟:
新增帳戶:開啟 NewCustomer 窗體。
填滿或取消訂單:開啟 FillOrCancel 窗體。
結束:關閉應用程式。
將瀏覽表單設為啟動表單
針對 C# 專案:
在 [方案總管] 中,開啟 [Program.cs]。
將行
Application.Run變更為:Application.Run(new Navigation());
針對 Visual Basic 專案:
在 [方案總管] 中,以滑鼠右鍵按兩下專案,然後選擇 [ 屬性]。
在 [項目設計工具] 中,選取 [應用程式] 索引標籤,然後選取 [啟動物件] 清單中的 [流覽]。
建立導覽表單的自動產生的事件處理程式
若要建立空的事件處理程式方法,請按兩下導覽表單上的三個按鈕。 雙擊按鈕會在設計工具的代碼檔中新增自動生成的代碼,這使得按鈕選擇可以觸發事件。
如果您決定直接將程式代碼複製並貼到程式碼檔案中,而不是在設計工具中使用按兩下動作,請確定您已將事件處理程式設定為正確的方法:
在表單程式代碼檔案的 [ 屬性 ] 視窗中,使用閃電工具列按鈕切換至 [ 事件 ] 索引標籤。
搜尋 Click 屬性,並確認其值為正確的事件處理程式方法。
新增導覽表單邏輯的程序代碼
在導覽表單的代碼頁中,完成三個按鈕選取事件處理程式的方法主體,如下列程式代碼所示。
/// <summary>
/// Opens the NewCustomer form as a dialog box,
/// which returns focus to the calling form when it is closed.
/// </summary>
private void btnGoToAdd_Click(object sender, EventArgs e)
{
Form frm = new NewCustomer();
frm.Show();
}
/// <summary>
/// Opens the FillorCancel form as a dialog box.
/// </summary>
private void btnGoToFillOrCancel_Click(object sender, EventArgs e)
{
Form frm = new FillOrCancel();
frm.ShowDialog();
}
/// <summary>
/// Closes the application (not just the Navigation form).
/// </summary>
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
新客戶窗體
當您輸入客戶名稱,然後選取 [ 建立帳戶 ] 按鈕時,NewCustomer 窗體會建立客戶帳戶,而 SQL Server 會傳回 IDENTITY 值作為新的客戶識別碼。 接著,您可以指定金額和訂單日期,然後選取 [ 下單] 按鈕,為新帳戶下單。
為 NewCustomer 窗體建立自動產生的事件處理程式
按兩下 NewCustomer 窗體上的每個按鈕,為四個按鈕建立空的 Click 事件處理程式。 按兩下按鈕還會在設計器程式碼檔案中新增自動生成的程式碼,以使按鈕選擇觸發事件。
新增 NewCustomer 表單邏輯的程式代碼
若要完成 NewCustomer 窗體邏輯,請遵循下列步驟:
將
System.Data.SqlClient命名空間帶入範圍,讓您不需要完整限定其成員的名稱。
將一些變數和協助程式方法新增至 類別。
// Storage for IDENTITY values returned from database. private int parsedCustomerID; private int orderID; /// <summary> /// Verifies that the customer name text box is not empty. /// </summary> private bool IsCustomerNameValid() { if (txtCustomerName.Text == "") { MessageBox.Show("Please enter a name."); return false; } else { return true; } } /// <summary> /// Verifies that a customer ID and order amount have been provided. /// </summary> private bool IsOrderDataValid() { // Verify that CustomerID is present. if (txtCustomerID.Text == "") { MessageBox.Show("Please create customer account before placing order."); return false; } // Verify that Amount isn't 0. else if ((numOrderAmount.Value < 1)) { MessageBox.Show("Please specify an order amount."); return false; } else { // Order can be submitted. return true; } } /// <summary> /// Clears the form data. /// </summary> private void ClearForm() { txtCustomerName.Clear(); txtCustomerID.Clear(); dtpOrderDate.Value = DateTime.Now; numOrderAmount.Value = 0; this.parsedCustomerID = 0; }
完成四個按鈕選取事件處理程式的方法主體。
/// <summary> /// Creates a new customer by calling the Sales.uspNewCustomer stored procedure. /// </summary> private void btnCreateAccount_Click(object sender, EventArgs e) { if (IsCustomerNameValid()) { // Create the connection. using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString)) { // Create a SqlCommand, and identify it as a stored procedure. using (SqlCommand sqlCommand = new SqlCommand("Sales.uspNewCustomer", connection)) { sqlCommand.CommandType = CommandType.StoredProcedure; // Add input parameter for the stored procedure and specify what to use as its value. sqlCommand.Parameters.Add(new SqlParameter("@CustomerName", SqlDbType.NVarChar, 40)); sqlCommand.Parameters["@CustomerName"].Value = txtCustomerName.Text; // Add the output parameter. sqlCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Int)); sqlCommand.Parameters["@CustomerID"].Direction = ParameterDirection.Output; try { connection.Open(); // Run the stored procedure. sqlCommand.ExecuteNonQuery(); // Customer ID is an IDENTITY value from the database. this.parsedCustomerID = (int)sqlCommand.Parameters["@CustomerID"].Value; // Put the Customer ID value into the read-only text box. this.txtCustomerID.Text = Convert.ToString(parsedCustomerID); } catch { MessageBox.Show("Customer ID was not returned. Account could not be created."); } finally { connection.Close(); } } } } } /// <summary> /// Calls the Sales.uspPlaceNewOrder stored procedure to place an order. /// </summary> private void btnPlaceOrder_Click(object sender, EventArgs e) { // Ensure the required input is present. if (IsOrderDataValid()) { // Create the connection. using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString)) { // Create SqlCommand and identify it as a stored procedure. using (SqlCommand sqlCommand = new SqlCommand("Sales.uspPlaceNewOrder", connection)) { sqlCommand.CommandType = CommandType.StoredProcedure; // Add the @CustomerID input parameter, which was obtained from uspNewCustomer. sqlCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Int)); sqlCommand.Parameters["@CustomerID"].Value = this.parsedCustomerID; // Add the @OrderDate input parameter. sqlCommand.Parameters.Add(new SqlParameter("@OrderDate", SqlDbType.DateTime, 8)); sqlCommand.Parameters["@OrderDate"].Value = dtpOrderDate.Value; // Add the @Amount order amount input parameter. sqlCommand.Parameters.Add(new SqlParameter("@Amount", SqlDbType.Int)); sqlCommand.Parameters["@Amount"].Value = numOrderAmount.Value; // Add the @Status order status input parameter. // For a new order, the status is always O (open). sqlCommand.Parameters.Add(new SqlParameter("@Status", SqlDbType.Char, 1)); sqlCommand.Parameters["@Status"].Value = "O"; // Add the return value for the stored procedure, which is the order ID. sqlCommand.Parameters.Add(new SqlParameter("@RC", SqlDbType.Int)); sqlCommand.Parameters["@RC"].Direction = ParameterDirection.ReturnValue; try { //Open connection. connection.Open(); // Run the stored procedure. sqlCommand.ExecuteNonQuery(); // Display the order number. this.orderID = (int)sqlCommand.Parameters["@RC"].Value; MessageBox.Show("Order number " + this.orderID + " has been submitted."); } catch { MessageBox.Show("Order could not be placed."); } finally { connection.Close(); } } } } } /// <summary> /// Clears the form data so another new account can be created. /// </summary> private void btnAddAnotherAccount_Click(object sender, EventArgs e) { this.ClearForm(); } /// <summary> /// Closes the form/dialog box. /// </summary> private void btnAddFinish_Click(object sender, EventArgs e) { this.Close(); }
填滿或取消窗體
FillOrCancel 窗體會執行查詢,以在您輸入訂單標識碼時傳回訂單,然後選取 [ 尋找訂單 ] 按鈕。 傳回的數據列會出現在唯讀數據格中。 如果您選取 [ 取消訂單 ] 按鈕,可以將訂單標示為已取消 (X),或者如果您選取 [ 填滿順序 ] 按鈕,可以將訂單標示為已填滿 (F)。 如果您再次選取 [ 尋找訂單] 按鈕,就會顯示更新的數據列。
建立 FillOrCancel 表單的自動產生的事件處理程式
按兩下 FillOrCancel 表單上的按鈕,為四個按鈕建立空的 Click 事件處理常式。 按兩下按鈕還會在設計器程式碼檔案中新增自動生成的程式碼,以使按鈕選擇觸發事件。
新增 FillOrCancel 表單邏輯的程式代碼
若要完成 FillOrCancel 窗體邏輯,請遵循下列步驟。
將下列兩個命名空間帶入範圍,讓您不需要完整限定其成員的名稱。
將變數和協助程式方法新增至 類別。
// Storage for the order ID value. private int parsedOrderID; /// <summary> /// Verifies that an order ID is present and contains valid characters. /// </summary> private bool IsOrderIDValid() { // Check for input in the Order ID text box. if (txtOrderID.Text == "") { MessageBox.Show("Please specify the Order ID."); return false; } // Check for characters other than integers. else if (Regex.IsMatch(txtOrderID.Text, @"^\D*$")) { // Show message and clear input. MessageBox.Show("Customer ID must contain only numbers."); txtOrderID.Clear(); return false; } else { // Convert the text in the text box to an integer to send to the database. parsedOrderID = Int32.Parse(txtOrderID.Text); return true; } }
完成四個按鈕選取事件處理程式的方法主體。
/// <summary> /// Executes a t-SQL SELECT statement to obtain order data for a specified /// order ID, then displays it in the DataGridView on the form. /// </summary> private void btnFindByOrderID_Click(object sender, EventArgs e) { if (IsOrderIDValid()) { using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString)) { // Define a t-SQL query string that has a parameter for orderID. const string sql = "SELECT * FROM Sales.Orders WHERE orderID = @orderID"; // Create a SqlCommand object. using (SqlCommand sqlCommand = new SqlCommand(sql, connection)) { // Define the @orderID parameter and set its value. sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int)); sqlCommand.Parameters["@orderID"].Value = parsedOrderID; try { connection.Open(); // Run the query by calling ExecuteReader(). using (SqlDataReader dataReader = sqlCommand.ExecuteReader()) { // Create a data table to hold the retrieved data. DataTable dataTable = new DataTable(); // Load the data from SqlDataReader into the data table. dataTable.Load(dataReader); // Display the data from the data table in the data grid view. this.dgvCustomerOrders.DataSource = dataTable; // Close the SqlDataReader. dataReader.Close(); } } catch { MessageBox.Show("The requested order could not be loaded into the form."); } finally { // Close the connection. connection.Close(); } } } } } /// <summary> /// Cancels an order by calling the Sales.uspCancelOrder /// stored procedure on the database. /// </summary> private void btnCancelOrder_Click(object sender, EventArgs e) { if (IsOrderIDValid()) { // Create the connection. using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString)) { // Create the SqlCommand object and identify it as a stored procedure. using (SqlCommand sqlCommand = new SqlCommand("Sales.uspCancelOrder", connection)) { sqlCommand.CommandType = CommandType.StoredProcedure; // Add the order ID input parameter for the stored procedure. sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int)); sqlCommand.Parameters["@orderID"].Value = parsedOrderID; try { // Open the connection. connection.Open(); // Run the command to execute the stored procedure. sqlCommand.ExecuteNonQuery(); } catch { MessageBox.Show("The cancel operation was not completed."); } finally { // Close connection. connection.Close(); } } } } } /// <summary> /// Fills an order by calling the Sales.uspFillOrder stored /// procedure on the database. /// </summary> private void btnFillOrder_Click(object sender, EventArgs e) { if (IsOrderIDValid()) { // Create the connection. using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString)) { // Create command and identify it as a stored procedure. using (SqlCommand sqlCommand = new SqlCommand("Sales.uspFillOrder", connection)) { sqlCommand.CommandType = CommandType.StoredProcedure; // Add the order ID input parameter for the stored procedure. sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int)); sqlCommand.Parameters["@orderID"].Value = parsedOrderID; // Add the filled date input parameter for the stored procedure. sqlCommand.Parameters.Add(new SqlParameter("@FilledDate", SqlDbType.DateTime, 8)); sqlCommand.Parameters["@FilledDate"].Value = dtpFillDate.Value; try { connection.Open(); // Execute the stored procedure. sqlCommand.ExecuteNonQuery(); } catch { MessageBox.Show("The fill operation was not completed."); } finally { // Close the connection. connection.Close(); } } } } } /// <summary> /// Closes the form. /// </summary> private void btnFinishUpdates_Click(object sender, EventArgs e) { this.Close(); }
測試您的應用程式
執行應用程式,並嘗試建立一些客戶和訂單,以確認一切如預期般運作。
若要驗證資料庫是否已根據您的變更進行更新:
在 [伺服器總管] 中開啟 [數據表] 節點。
以滑鼠右鍵按兩下 [客戶 ] 和 [ 訂單] 節點,然後選擇 [ 顯示資料表數據]。
相關內容
- 適用於 .NET 的 Visual Studio 資料工具