本文整理自《C# 網絡應用編程基礎練習題與答案(八)》,涵蓋 **連線式架構** (`SqlConnection`/`SqlCommand`/`SqlDataReader`)、**斷開式架構** (`SqlDataAdapter`/`DataSet`/`DataTable`)、**存儲過程參數化** 等 ADO.NET 核心實戰技能。
需求:使用 `SqlDataReader` 計算 `MyTable2` 中按學號前兩位 (年級) 分組的平均成績,顯示於 `ListBox`。
private void btnQueryAvg_Click(object sender, EventArgs e)
{
listBox.Items.Clear();
listBox.Items.Add("年級\t平均成績");
string connStr = Properties.Settings.Default.MyDatabaseConnectionString;
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(
"SELECT SUBSTRING(學號, 1, 2) AS 年級, AVG(成績) AS 平均成績 " +
"FROM MyTable2 GROUP BY SUBSTRING(學號, 1, 2)", conn))
{
try
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
listBox.Items.Add($"{reader["年級"]}級\t{reader["平均成績"]:F2}");
}
}
}
catch (Exception ex)
{
MessageBox.Show($"查詢失敗: {ex.Message}");
}
}
}
需求:查詢成績 < 60 的學生學號、姓名、性別、成績。
private void btnFailed_Click(object sender, EventArgs e)
{
listBox.Items.Clear();
listBox.Items.Add("學號\t姓名\t性別\t成績");
string connStr = Properties.Settings.Default.MyDatabaseConnectionString;
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(
"SELECT 學號, 姓名, 性別, 成績 FROM MyTable2 WHERE 成績 < 60", conn))
{
try
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
listBox.Items.Add($"{reader[0]}\t{reader[1]}\t{reader[2]}\t{reader[3]}");
}
}
}
catch (Exception ex)
{
MessageBox.Show($"查詢失敗: {ex.Message}");
}
}
}
需求:`Form_Load` 時用 `SqlDataAdapter` 填充 `DataSet`,以 `"[編碼] 名稱"` 格式填入 `ComboBox`。
private void Form1_Load(object sender, EventArgs e)
{
string connStr = Properties.Settings.Default.MyDatabaseConnectionString;
using (var conn = new SqlConnection(connStr))
using (var adapter = new SqlDataAdapter("SELECT * FROM MyTable1", conn))
{
var ds = new DataSet();
try
{
adapter.Fill(ds, "MyTable1");
foreach (DataRow row in ds.Tables["MyTable1"].Rows)
{
comboBox.Items.Add($"[{row[0]}] {row[1]}");
}
if (comboBox.Items.Count > 0) comboBox.SelectedIndex = 0;
}
catch (Exception ex)
{
MessageBox.Show($"載入失敗: {ex.Message}");
}
}
}
| 特性 | 連線式 (DataReader) | 斷開式 (DataAdapter/DataSet) |
|---|---|---|
| 連線狀態 | 查詢期間**持續開啟** | 填充後**立即關閉** |
| 資料游標 | **唯讀、順向** (`Read()`) | **可隨機存取、可修改**、支援關聯/約束 |
| 記憶體 | **流式**,佔用極低 | **全量載入**記憶體 |
| 適用場景 | 大量資料、單次遍歷、報表串流 | 需繫結 UI 控制項、離線編輯、多表關聯 |
填空題:
string connString = "server=localhost;Integrated Security=SSPI;database=pubs";
SqlConnection conn = new SqlConnection(connString); // ← 正確:用連線字串建構
string strsql = "select * from MyTable2";
SqlDataAdapter adapter = new SqlDataAdapter(strsql, conn); // ← 正確:SQL + 連線
DataSet dataset = new DataSet();
adapter.Fill(dataset, "MyTable2"); // ← 正確:填充至 DataSet 並指定表名
this.dataGridView1.DataSource = dataset.Tables["MyTable2"];
private void btnAdults_Click(object sender, EventArgs e)
{
string connStr = Properties.Settings.Default.MyDatabaseConnectionString;
using (var conn = new SqlConnection(connStr))
using (var adapter = new SqlDataAdapter(
"SELECT id, xm, xb, nl FROM person WHERE nl > 18 ORDER BY id", conn))
{
var ds = new DataSet();
try
{
adapter.Fill(ds, "person");
dataGridView.DataSource = ds.Tables["person"];
// 禁止使用者編輯
dataGridView.AllowUserToAddRows = false;
dataGridView.AllowUserToDeleteRows = false;
dataGridView.ReadOnly = true; // 整體唯讀
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
問題:`@surname nvarchar(2)` 改為 `@surname nchar(2)`,結果是否正確?
答案:**不一定。**
private void btnCountByChar_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtChar.Text))
{
MessageBox.Show("請輸入漢字");
return;
}
string connStr = Properties.Settings.Default.MyDatabaseConnectionString;
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand("SelectFilterStudentsNum", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@surname", txtChar.Text.Trim());
// OUTPUT 參數必須指定 Direction
var outParam = cmd.Parameters.Add("@record", SqlDbType.Int);
outParam.Direction = ParameterDirection.Output;
try
{
conn.Open();
cmd.ExecuteNonQuery(); // 執行存儲過程
int count = (int)outParam.Value;
MessageBox.Show($"有 {count} 條記錄包含「{txtChar.Text}」");
}
catch (Exception ex)
{
MessageBox.Show($"統計失敗: {ex.Message}");
}
}
}
CREATE PROCEDURE SelectFilterStudentsNum
@surname NVARCHAR(10),
@record INT OUTPUT
AS
BEGIN
SELECT @record = COUNT(*)
FROM MyTable2
WHERE 姓名 LIKE '%' + @surname + '%';
END