## What is ADO.NET
  ADO.NET(ActiveX Data Objects .NET)是由Microsoft提供的一個數據訪問技,主要用於.NET與資料庫(SQL)或是其他數據來源的相互連結,是.NET系列中重要的一部分
## DataSet & DataReader
  在ASP.NET中的**DataSource控制項(SqlDataSource、AccessDataSource)** 不算是完整的 ADO.NET,他是基於ADO.NET簡化後的"小精靈",僅用於ASP.NET的WebForm網頁程式中,其中這些控制項內有`DataSet`和`DataReader`是屬於ADO.NET的基礎核心之一

DataReader與DataSet與他們搭配的Connection、Command、DataAdapter等都隸屬於==System.Data==這個命名空間內

圖片來源:mis2000 ASP.NET 專題實務 I
:::info
Web Application較多Server的要求(Request),因此網頁較適合搭配輕量化及速度快的DateReader而DataSet較適用於Windows Form(exe)
原因:在WebForm情況下,由於每次處理每次都會重新創建WebForm
這過程不僅需要反覆調用資源重建頁面,也需要重建DataSet過程會非常消耗效能,所以在Web Application使用上還是建議使用DataReader較為適當
:::
:::spoiler GPT補充
1. **DataReader 的應用**:由於 Web Application 需要處理較多的 Server 請求(Request),在這種情況下,效能和速度變得非常重要。DataReader 是一種輕量級、只進讀取(Forward-only)的數據讀取機制,它不需要在內存中存儲整個數據集,而是逐行讀取數據,因此在處理大量數據時速度更快,佔用的資源也相對較少。所以,在 Web Application 中,特別是在 ASP.NET 的 WebForm 網頁程式中,搭配 DataReader 可以更高效地處理數據。
2. **DataSet 的應用**:DataSet 是一個記憶體中的數據容器,它可以包含多個 DataTable,用於存儲和處理數據。而在 Windows Forms 應用程式(.exe)中,因為應用程序較為靜態,不像 WebForm 需要頻繁重新創建,所以資源消耗相對不那麼敏感。在這種情況下,DataSet 可以更方便地用於將數據緩存並進行複雜的操作,尤其是當你需要在應用程序中離線處理數據時,DataSet 提供了更多的彈性。
:::
### DataReader
以簡單的數據存取來說DataReader是較為快速便利的做法,但要注意以下幾點
* DataReader只提供唯讀(read-only)和順向(Foward)資料指標,由於先天的限制DataReader也不能做分頁(Page)的功能
* 每一次的資料庫連線(Connection),只能使用一個DataReader,所以說如果已經開啟一個DataReader只要在沒有關閉的情況是無法開啟第二個
:::info
1. **唯讀 (Read-only)**:意味著 DataReader 是用於讀取數據而不是修改數據。一旦用於讀取數據,它不具備直接對數據源進行修改的能力。例如,您不能使用 DataReader 直接對數據庫中的數據進行增、刪、改的操作。
2. **順向 (Forward)**:意味著 DataReader 的資料指標是單向的,它只能向前遍歷數據,無法向後或隨機訪問數據。當您使用 DataReader 讀取數據時,它將按照查詢結果的順序一行一行地向前移動,而且只能向前移動,不能返回上一行或跳到特定行。
3. **先天限制** 像是剛才提到的由於他是**順向**,所以他無法在遍歷過程中回到之前的位置或者直接跳到特定的頁數。但這部分可以使用SQL語法克服,後續會再說明(在需要分頁功能的情況下,常見的做法是使用其他數據庫查詢方式(例如 SQL 的 `LIMIT` 和 `OFFSET`,或者存儲過程)來實現分頁,然後再將查詢結果放入 DataReader 或者 DataSet 中進行處理。)
4. **只能使用一個DataReader** 這個限制是由 ADO.NET 的設計決定的,主要是為了保證資料的一致性和可靠性。一旦 DataReader 打開了連線並開始讀取數據,它會佔用連線,直到該 DataReader 關閉。這樣可以確保在數據讀取過程中不會有其他操作影響到該連線的狀態,從而保證數據讀取的穩定性。([可參閱YT:MIS2000Lab](https://youtu.be/oY7jd0ABXeM))
:::
## 如何連結資料庫
在ASP.NET (WebForm)與SQL連結的程序大概如下:
```mermaid
graph TD
a[連結資料庫]-->b[執行SQL指令]
b-->c[查詢資料產生畫面]
c-->d[關閉資料庫連結釋放資源]
```
### **連結資料庫**
  首先我們需要將 ADO.NET 連結 SQL 資料庫所需的連接資訊,如連接字串 (Connection String)、資料庫位置、認證方式、使用者名稱等,保留在 Web.config 檔案中。
#### **ConnectionString**
```xml!
<configuration>
<connectionStrings>
<add name="MyDbConnection" connectionString="Data Source=myserver;Initial Catalog=mydatabase;User Id=myuser;Password=mypassword;" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
```
現在我在Web Form的 Web.config 檔案中加入這段ConnectionString
我先定義了一個名為 "MyDbConnection" 的連接字串設定。讓我們一步一步來詳細解釋這段:
1. `<configuration>`:Web.config 檔案的根元素,所有的配置設定都會放在這個元素內,是整個文件的主要結構。
2. `<connectionStrings>`:用於存儲連接字串的設定。在這個區塊中,你可以定義多個連接字串。
3. `<add>`:這是 `<connectionStrings>` 區塊中的子元素,用於添加一個新的連接字串設定。
4. `name="MyDbConnection"`:定義連結字串的名稱,可以自行命名,後續在程式碼中可用這個名稱來引用連接字串。
5. `connectionString="Data Source=myserver;Initial Catalog=mydatabase;User Id=myuser;Password=mypassword;"`:這是連接字串本身,包含了連接資料庫所需的資訊。
- `Data Source=myserver`:這裡指定了資料庫的伺服器位置或 IP 地址。"myserver" 是一個代稱,你需要將它替換為實際的伺服器名稱或 IP 地址。以我們的SQL來說我就會設定自己的伺服器名稱(LAPTOP-H05SQCHU\SQLEXPRESS)
- `Initial Catalog=mydatabase`:這裡指定了連接的資料庫名稱,"mydatabase" 是一個代稱,你需要將它替換為實際的資料庫名稱。

- `User Id=myuser`:這裡指定了連接資料庫所使用的使用者名稱,"myuser" 是一個代稱,你需要將它替換為實際的使用者名稱。**(如果是使用Windows 身份驗證 (伺服器驗證)不須添加)**
- `Password=mypassword`:這裡指定了連接資料庫所使用的密碼,"mypassword" 是一個代稱,你需要將它替換為實際的密碼。**(如果是使用Windows 身份驗證 (伺服器驗證)不須添加)**
6. `providerName="System.Data.SqlClient"`:這裡指定了使用的資料提供者,"System.Data.SqlClient" 是指 Microsoft SQL Server 的 ADO.NET 資料提供者。當然,如果你使用其他類型的資料庫,就需要指定相對應的資料提供者。
7. `Integrated Security=True`:用於指定使用 Windows 身份驗證 (Windows Authentication) 來連接資料庫。當這個選項設置為 `True` 時,ADO.NET 會使用目前執行程式的使用者的 Windows 登入資訊來進行身份驗證。
總結一下,這段配置定義了一個名為 "MyDbConnection" 的連接字串設定,用於連接到指定的資料庫伺服器和資料庫,並使用指定的使用者名稱和密碼來認證。這樣一來,在程式碼中使用
```csharp!
ConfigurationManager.ConnectionStrings["MyDbConnection"].ConnectionString
```
就可以獲取這個連接字串,並使用它來建立與資料庫的連線。
#### 💡💡💡迅速生成ConnectionString!SqlDataSource💡💡💡
ConnectionString這個步驟非常重要,但是非常繁瑣又難記。這邊我們可以使用SqlDataSource小精靈來完成這段艱難的任務
* Step1.在WebForm設計模式中拉取SqlDataSource進畫面

* Step2.點擊SqlDataSource並選擇"設定資料來源"

* Step3.選擇新增連結,選擇資料來源/輸入伺服器名稱/驗證並選擇你需要的資料庫名稱(這邊我選擇MS Server當作來源並選擇本地伺服器,驗證使用Windows驗證並選擇一個資料庫)

* Step4.點選"連結字串"產生ConnectionString

* Step5. 勾選"是,將這個連結儲存為(Y)儲存,將連結字串的內容命名並將他儲存在Web Config中

* Step.6 這邊可以勾選自己想要的內容,系統會幫你轉換成SQL語法

* Step.7 最後可以進行測試,OK的話就可以點選"完成"

### **使用GridView連結資料庫**
**前情提要** :這邊我已經用SqlDataSource建立了一個connetionString,並在SQL Server中建立了一個簡易的資料庫
* 資料庫

* ConnectionString
```csharp!
<connectionStrings>
<add name="MessageBoardConnectionString" connectionString="Data Source=LAPTOP-H05SQCHU\SQLEXPRESS;Initial Catalog=MessageBoard;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
```
接下來我們將Gridview元件從**工具箱**拖曳至設計模式中,點選GridView並將資料來源改為`SqlDataSource`,在下方的設定資料庫來源可以"重新設定資料連結",包含ConnectionString及想顯示的資料庫欄位
* 在GridView中設定資料來源


* 在重新設定資料連結中設定GridView呈現的資料數據


* 退出設計模式後就可以去畫面頁執行看看囉

以上就是運用SqlDataSource與GridView資料連結產生的布告欄效果。但是實際專案在製作上可能會更傾向於在後置程式碼中寫入ADO.NET來與資料庫進行連結
### 欸?SqlDataSource這麼好用為什麼不能用?
如同開同所說 SqlDataSource是ADO.NET中的一個自動化程序,他可以提供一些簡單的SQL查詢用來顯示畫面,但是SqlDataSource會受到一些性能上的限制:
* **自訂效果和高階查詢能力:** 在 ADO.NET 中,可以撰寫自訂的查詢語句和儲存過程,實現更複雜的資料庫操作。讓你能夠更好適應特定的業務需求,而 `SqlDataSource` 則可能在處理複雜查詢時受到限制。
* **手動控制連線:** `SqlDataSource` 本身擁有自動處理連線的開啟和關閉,假若有頻繁的查詢需求,`SqlDataSource` 會對於頻繁的資料庫操作導致效能降低,我們可以透過ADO.NET手動管理連線,可以更有效利用連線,降低連線的開銷。
* **綜合使用的建議:** 基本上兩者都可以使用,例如在簡單的資料綁定場景下,可以使用 `SqlDataSource` 以減少程式碼量並快速實作。而在需要更高級控制和複雜查詢的情況下,則可以選擇使用 ADO.NET,以更好滿足專案需求和性能優化目標。
**Bind & Eval**
摘要:資料繫結Eval方法 v.s. Bind方法
ASP.NET 2.0 的Data-Binding 資料繫結語法表示符為「<% # %>」,而裡面必須搭配Eval或Bind指令,也就是<%#Eval("變數名稱")%> 或者<%#Bind("變數名稱")%>,"變數名稱"則為資料來源欄位,而Eval或Bind兩個方法是有差異的,以下是說明:
.**Eval**:Eval是用於單向資料繫結,資料是**唯讀**的顯示。
.**Bind**:Bind則是雙向的資料繫當,不但能讀取資料,更具有Insert、Update、Delete功能,所以若您需要編輯**更新、新增與刪除功能**使用本方法。
相對於ASP.NET 1.0舊語法DataBinder.Eval(Container.DataItem,"變數名稱")建議您在GridView、DetailsView及FormView應優先使用新的宣告語法。
資料來源:聖殿祭司的ASP.NET 2.0專家技術手冊-使用C#
記得段開資料來源後要選否,不然設定好的標題都會消失

## ADO.NET實際CRUD程式碼(以留言板為例)
### 1\. 讀取(Read)
這部分代碼用於從資料庫中讀取資料,並顯示在Web Form的GridView控件中。
```csharp!
string SQLstr = "SELECT * From Home order by InintDate Desc;";
using (SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["BulletinBoardConnectionString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(SQLstr, conn);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
// 取得資料源
GridView1.DataSource = dr;
// 取得ID下的所有資料
GridView1.DataKeyNames = new string[] { "ID" };
// 用於綁定資料
GridView1.DataBind();
cmd.Cancel();
dr.Close();
conn.Close();
}
```
### 2\. 創建(Create)
以下是一個用於向資料庫插入新記錄的示範。
```csharp!
string insertSQL = "INSERT INTO Home (ColumnName1, ColumnName2) VALUES (@Value1, @Value2);";
using (SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["BulletinBoardConnectionString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(insertSQL, conn);
// 用參數化查詢來防止SQL注入
cmd.Parameters.AddWithValue("@Value1", value1);
cmd.Parameters.AddWithValue("@Value2", value2);
conn.Open();
cmd.ExecuteNonQuery(); // 執行非查詢指令,不返回任何資料
conn.Close();
}
```
### 3\. 更新(Update)
更新現有資料庫記錄
```csharp!
string updateSQL = "UPDATE Home SET ColumnName1 = @NewValue1 WHERE ID = @ID;";
using (SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["BulletinBoardConnectionString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(updateSQL, conn);
cmd.Parameters.AddWithValue("@NewValue1", newValue1);
cmd.Parameters.AddWithValue("@ID", id);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
```
### 4\. 刪除(Delete)
從資料庫中刪除記錄。
```csharp!
string deleteSQL = "DELETE FROM Home WHERE ID = @ID;";
using (SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["BulletinBoardConnectionString"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(deleteSQL, conn);
cmd.Parameters.AddWithValue("@ID", id);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
```