--- tags: 110-2視窗程式設計 --- # 實作:操作資料庫 上次帶領同學實地對資料庫做連線,並且應用在會員登入的情境之下,接下來幫助同學實地進行資料庫系統操作工作,讓你能夠透過視窗程式來做資料的**查詢(或取得)、新增、修改(或更新)與刪除**。 ## 程式功能 這次我們會設計一個簡單的操作,使用者能夠連線資料庫,並且查詢出所有資料,然後可以修改、新增與刪除裡面的資料。 其實大多數的資訊系統都是類似的工作,你會需要看到資料顯示在程式裡面,你可能想修改資料內容,如果有新的資料要加進去,你會新增這些資料到系統中。同樣的,假如有些資料不需要了,你會進行刪除工作。因此資料庫系統的設計,也就主要包括了: **1. 查詢(或取得) 2. 新增 3. 修改(或更新) 4. 刪除** 這邊我們透過一個簡單的案例,告訴同學如何以程式進行這四個主要的工作,下次你使用任何資訊系統,你也會發現其實多半也就是這四種工作。 ![](https://i.imgur.com/xtpdWif.png =500x) ## 開啟新專案 開啟新專案之前有教學過,如果你忘記了或不太熟悉,請點選[這裡](https://hackmd.io/sFFV6T2oT0-ysHotbIybhw?view#WPF-%E7%9A%84%E5%B0%88%E6%A1%88%E8%A8%AD%E5%AE%9A)。 :::success 我們的專案名稱可以叫做「Datatable」,簡單就好。 ::: ## 開始吧! 還記得第二部分的基本視窗程式設計嗎?同樣的,我們依照之前說過的兩個主要程式設計流程來設計: 1. 介面基本設計 2. 程式撰寫 因此,我們也是先初步設計介面,再來進行程式撰寫。 ## 第一步:進行介面基本設計 和過去的範例程式都類似,請你先從工具箱拉控制項元件進來,需要 5 個輸入文字框、4 個按鍵。其中,這次我們使用一個新的控制項稱為「**==資料網格(DataGird)==**」,像這樣的控制項很適合顯示表格資料,例如下圖。由於資料庫的資料多半是表格型態的,所以我們使用資料網格來顯示資料庫的查詢結果。 ![](https://i.imgur.com/jxL2ZOS.png) 將每一個控制項設定一個名稱,例如以下的範例名稱: :::info 1. 資料網格:dgData 2. ID輸入文字框:txtId 3. 姓名輸入文字框:txtName 4. 帳號輸入文字框:txtAccount 5. 密碼輸入文字框:txtPassword 6. 管理者輸入文字框:txtAdmin 7. 顯示所有資料按鍵:btnLogin 8. 更改按鍵:btnUpdate 9. 新增按鍵:btnInsert 10. 刪除按鍵:btnDelete ::: ![](https://i.imgur.com/ksRQzs0.png) ## 第二部分:程式碼撰寫 接下來,由於我們要連線的資料庫叫做 MySQL 資料庫管理系統,如果要用 Visual Studio 2019 來連線到 MySQL,必須要使用 NuGet 安裝第三方的 MySQL.Data 套件程式庫。 請參考這個[連結](https://hackmd.io/FWm-tgyaSTivwWyJ6ol_iA?view#%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86%EF%BC%9A%E7%A8%8B%E5%BC%8F%E7%A2%BC%E6%92%B0%E5%AF%AB),來安裝套件。 ### 事件綁定 然後我們就要把程式寫進來,讓程式可以運作,你可以先將所有按鍵都先做一次 click 事件綁定。以下的程式碼你可先參考,將所需要的第 1 行、第15-18行先行置入。 ```csharp= using System.Data; // 導入 DataTable 函式庫 using MySql.Data.MySqlClient; // 導入第三方 MySQL.Data 套件的連線程式庫 namespace Datatable { /// <summary> /// MainWindow.xaml 的互動邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } // 資料庫連線字串,Server:資料庫管理系統的位址(IP或網址)、Uid:可以使用資料庫的帳號、Pwd:可以使用資料庫的密碼、database:要連線的資料庫名稱 private string connstr = "Server=120.101.58.4;Uid=user;Pwd=user;database=login"; // 建立一個資料表物件 dt,我們把資料庫中的資料抓出來之後,放到這個物件中,然後顯示在表格上 private DataTable dt = new DataTable(); private void btnQuery_Click(object sender, RoutedEventArgs e) { } private void btnUpdate_Click(object sender, RoutedEventArgs e) { } private void btnInsert_Click(object sender, RoutedEventArgs e) { } private void btnDelete_Click(object sender, RoutedEventArgs e) { } } } ``` 一樣為了要對資料庫連線,必須要先設定連線字串,connstr 變數就儲存了對 MySQL 資料庫的連線字串。 ### 資料表 DataTable 物件基礎認識 其中我們這次使用一個新的資料型態,叫做「資料表(DataTable)」物件,這種變數顧名思義,就是用來放表格的。你可以這樣想,既然資料庫查詢出來的結果,本來就是表格的樣子,那麼像這樣的資料表物件最適合來存放資料庫查詢結果,因此我們使用這種物件來儲存查詢結果。 宣告一個資料表的語法如下: ```csharp DataTable dt = new DataTable(); ``` 我們宣告一個資料表物件之後,將查詢結果放到這個物件裡面,然後用程式顯示在畫面上。如同下圖的概念。 ![](https://i.imgur.com/xyutmss.png) ### 將資料庫資料查詢結果放到資料表物件 接下來我們要實作將資料庫查詢的結果,放到資料表物件中,請將以下程式碼放到你的專案裡面。 你可以看的到,以下程式是一個函式,它進行的工作就是和資料庫連線。連線成功後,使用一種叫做「資料庫連接器(Adapter)」與資料庫做橋梁,對資料庫下 SQL 操作指令進行查詢,再將查詢結果放到資料表物件中。最後將資料表物件的內容,顯示在資料網格(dgData)中,你就可以在程式畫面上看到資料內容。 另外,我們也需要在資料網格設定為「綁定資料表」,請到資料網格的屬性中,找尋一個「ItemsSource」項目,點選右側的小正方形,再選擇「自訂運算式」,輸入「{ Binding }」,這樣才能讓資料表物件與資料網格進行連動。 ![](https://i.imgur.com/X4PLF8y.png) 然後你可以把這個函式的執行,放到「顯示所有資料」按鍵的 Click 事件綁定。這時你可以測試程式,按下「顯示所有資料」按鍵,就可以看到左側的資料網格中出現了查詢結果。 ```csharp= // 查詢並顯示資料的函式 private void GetAllData() { try { // 使用 using 語法來進行資料庫連線 using (var conn = new MySqlConnection(connstr)) { conn.Open(); // 開啟資料庫連線 // 使用 using 語法來設定資料庫的連接器 using (var da = new MySqlDataAdapter()) { string sqlSelectAll = "SELECT * FROM users"; // SQL指令 da.SelectCommand = new MySqlCommand(sqlSelectAll, conn); // 執行查詢 dt.Clear(); // 清除資料表物件 da.Fill(dt); // 將查詢到的資料放到資料表物件 dgData.DataContext = dt; // 讓資料表物件顯示在資料網格裡面 } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); // 如果中間的資料庫連線流程有問題,就會跳出錯誤訊息 } } private void btnQuery_Click(object sender, RoutedEventArgs e) { GetAllData(); // 按下「顯示所有資料」按鍵,執行查詢並顯示資料的函式 } ``` ![](https://i.imgur.com/dbEsW6h.png) ### 點選資料,顯示在輸入對話框之中 然後我們要設計一個簡單機制,當你選擇資料網格的其中一列資料,也會同時在右側的輸入文字框中出現,為什麼要這樣設計呢?因為我們希望點選一列資料,可以讓使用者進行更改或刪除的動作。因此,必須要讓特定資料被顯示出來,才能做這樣的更改與刪除。 當然你要做到這樣的效果,必須也要找到這個資料網格的特定事件,請回到視窗設計屬性視窗的事件清單中,找尋一個「**SelectionChanged 事件**」,並且綁定它,如下圖 ![](https://i.imgur.com/Tkaqc6c.png) 然後將以下的程式碼放到這個事件綁定中。 ```csharp= private void dgData_SelectionChanged(object sender, SelectionChangedEventArgs e) { int selected_index = dgData.SelectedIndex; // 取得你按的是第幾列的資料? // 因為要取得資料顯示在輸入文字框中,必須將在DataGrid中所選擇的列,與資料表物件的資料列位置彼此對應 // 但可能DataGrid沒有資料顯示(selected_index = -1),或者選到最下面的一列(selected_index = 資料表物件總列數),造成與資料表物件無法相對應,會產生錯誤,因此必須要做判斷 if (selected_index >= 0 && selected_index != dt.Rows.Count) { txtId.Text = dt.Rows[selected_index].ItemArray[0].ToString(); txtAccount.Text = dt.Rows[selected_index].ItemArray[1].ToString(); txtPassword.Text = dt.Rows[selected_index].ItemArray[2].ToString(); txtName.Text = dt.Rows[selected_index].ItemArray[3].ToString(); txtAdmin.Text = dt.Rows[selected_index].ItemArray[4].ToString(); } } ``` 這一段的程式很單純,其實就先找出你你按的是第幾列的資料?取得第幾列的數值後,做一個簡單的判斷,避免數值小於 0 或者剛好等同於資料表物件的資料數。 因為要取得資料顯示在輸入文字框中,必須將在DataGrid中所選擇的列,與資料表物件的資料列位置彼此對應。不過,有可能資料網格中沒有資料,也就是點選資料網格後,取得的第幾列數值為 -1,或者選到最下面的一列,造成與資料表物件無法相對應,會產生錯誤,因此必須要做判斷。 如果我們選到的資料都是有資料的,就會在資料物件中相對應的資料列取出,逐一顯示在輸入文字框之中。 現在你測試程式,只要點選表格中的任何一筆資料,就會顯示在輸入文字框之中。 ![](https://i.imgur.com/QWhtuDg.png) ### 資料修改 接下來我們設計資料修改的機制,請在「更改」按鍵的 click 事件綁定中放入以下程式內容: ```csharp= private void btnUpdate_Click(object sender, RoutedEventArgs e) { try { using (var conn = new MySqlConnection(connstr)) { conn.Open(); // 使用 using 語法來設定資料庫的操作命令 using (MySqlCommand cmd = new MySqlCommand("UPDATE users SET account=@account, password=@password, name=@name WHERE id=@id", conn)) { cmd.Parameters.AddWithValue("@account", txtAccount.Text); // 將輸入文字框的資料與資料庫操作指令做對應 cmd.Parameters.AddWithValue("@password", txtPassword.Text); cmd.Parameters.AddWithValue("@name", txtName.Text); cmd.Parameters.AddWithValue("@id", txtId.Text); cmd.ExecuteNonQuery(); // 執行資料庫操作 } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); // 如果中間的資料庫連線流程有問題,就會跳出錯誤訊息 } finally { GetAllData(); // 執行完操作後,重新整理資料 } } ``` 以上的程式和之前資料庫查詢的方式都有點類似,也是要先設定SQ操作指令,這邊我們使用的指令稱為「**更新指令(Update)**」,並且我們連結輸入文字框的資料,最後使用「ExecuteNonQuery()」執行資料庫操作,真實地將資料庫中的資料進行修改。 並且在 finally 的階段,還會再重新查詢一次資料,這是因為修改後的資料還是要再查詢一次,才能同步更新在資料網格中。 這時你進行程式測試,點選表格中的任何一筆資料,然後在輸入文字框中修改資料,按下「更改」按鍵,你就會看到資料也同步修改在左側的資料網格中。 ![](https://i.imgur.com/S5j8NvH.png) ### 資料新增與刪除 同樣的,資料的新增與刪除其實都與更新類似,請在「新增」、「刪除」按鍵的 click 事件綁定中放入以下程式內容: ```csharp= private void btnInsert_Click(object sender, RoutedEventArgs e) { try { // 使用 using 語法來進行資料庫連線 using (var conn = new MySqlConnection(connstr)) { conn.Open(); using (MySqlCommand cmd = new MySqlCommand("INSERT INTO users (account, password, name) VALUES (@account, @password, @name)", conn)) { cmd.Parameters.AddWithValue("@account", txtAccount.Text); cmd.Parameters.AddWithValue("@password", txtPassword.Text); cmd.Parameters.AddWithValue("@name", txtName.Text); cmd.ExecuteNonQuery(); } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); // 如果中間的資料庫連線流程有問題,就會跳出錯誤訊息 } finally { GetAllData(); } } private void btnDelete_Click(object sender, RoutedEventArgs e) { try { using (var conn = new MySqlConnection(connstr)) { conn.Open(); using (MySqlCommand cmd = new MySqlCommand("DELETE FROM users WHERE id=@id", conn)) { cmd.Parameters.AddWithValue("@id", int.Parse(txtId.Text)); cmd.ExecuteNonQuery(); } } } catch (Exception ex) { MessageBox.Show(ex.ToString()); // 如果中間的資料庫連線流程有問題,就會跳出錯誤訊息 } finally { GetAllData(); } } ``` 你也可以看到,其實這兩個按鍵的程式內容,基本上都類似,主要差異也是在 SQL 操作指令上面,如果是新增資料,使用的是「Insert」指令,如果是刪除資料,則是使用「Delete」指令 ## 結語 以上的程式我們讓同學初步理解,利用資料庫其實能夠儲存各種樣式的資料,只要你能夠進行資料庫連線,就能進行查詢、新增、修改與刪除等工作。大多數的資訊系統其實都是類似的形式,現代的各種資訊系統簡單來看,也都是類似的形式。