1. Join 操作:結合多個表

// ------------------------------------------------------------
// Join:透過 CategoryId 將 Products 和 Categories 資料表進行關聯查詢

LabDbEntities context = new LabDbEntities(); // 建立資料庫上下文
var query = from p in context.Products
            join c in context.Categories on p.CategoryId equals c.CategoryId // 透過 CategoryId 進行內部連接(Join)
            select new {
                CategoryName = c.CategoryName, // 選擇分類名稱
                ProductName = p.ProductName,   // 選擇產品名稱
                UnitsInStock = p.UnitsInStock  // 選擇產品庫存數量
            };
dataGridView1.DataSource = query.ToList(); // 將查詢結果綁定到 DataGridView 以便顯示

2. 使用 Navigation Properties

// ------------------------------------------------------------
// Navigation Properties:透過導航屬性取得關聯資料

LabDbEntities context = new LabDbEntities(); // 建立資料庫上下文
Product obj = context.Products.Find(2);      // 使用 Find 方法找到 ProductId 為 2 的產品
Category c = obj.Category;                   // 使用導航屬性直接存取與該產品關聯的 Category 物件
button1.Text = c.CategoryName;               // 將分類名稱顯示在按鈕上

3. Concurrency Model:處理並發衝突

// ------------------------------------------------------------
// Concurrency Model:處理多使用者同時修改數據的情況

try {
    db.SaveChanges(); // 嘗試保存變更
}
catch (System.Data.Entity.Infrastructure.DbUpdateConcurrencyException ex) {
    // 當發生並發衝突時捕獲異常
    LabDbEntities db2 = new LabDbEntities();   // 建立另一個上下文來重新取得資料
    Product p = db2.Products.Find(2);          // 取得 ProductId 為 2 的產品
    p.UnitsInStock -= 20;                      // 減少庫存
    db2.SaveChanges();                         // 保存變更
}

4. Multi-User Lab:模擬多使用者操作與資料鎖定

// ------------------------------------------------------------
// Multi-User Lab:模擬多使用者同時修改庫存數據的情境

// 初始化表單時,採用讀取未提交 (Read Uncommitted) 隔離層級進行查詢
public Form1() {
    InitializeComponent();

    LabDbEntities context = new LabDbEntities(); // 建立資料庫上下文
    var t = context.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted); // 開啟事務,使用 Read Uncommitted 隔離層級
    Product obj = context.Products.Find(2);      // 查詢 ProductId 為 2 的產品
    t.Commit();                                  // 提交事務
    label1.Text = obj.UnitsInStock.ToString();   // 顯示庫存數量
}

// 按下購買按鈕時,模擬減少庫存的操作
private void BuyButton_Click(object sender, EventArgs e) {
    LabDbEntities context = new LabDbEntities();  // 建立資料庫上下文
    Product obj = context.Products.Find(2);       // 查詢 ProductId 為 2 的產品
    obj.UnitsInStock -= 1;                        // 將庫存減少 1
    System.Threading.Thread.Sleep(1000 * 10);     // 模擬延遲,模擬多使用者同時操作情境
    context.SaveChanges();                        // 保存變更
    (sender as Button).Text = "Done";             // 按鈕顯示完成
}

// 按下另一個購買按鈕時,模擬使用 SQL 查詢來鎖定資料
private void BuyButtonV2_Click(object sender, EventArgs e) {
    LabDbEntities context = new LabDbEntities();  // 建立資料庫上下文
    var t = context.Database.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted); // 使用 Read Uncommitted 隔離層級開啟事務
    Product obj = context.Products.SqlQuery("select * from products with (xlock) where productId = 2").FirstOrDefault();
    // 使用 SQL 查詢並鎖定 ProductId 為 2 的資料行,防止其他用戶同時更新
    obj.UnitsInStock -= 1;                         // 減少庫存
    context.SaveChanges();                         // 保存變更
    System.Threading.Thread.Sleep(1000 * 10);      // 模擬延遲
    t.Commit();                                    // 提交事務
}

教學重點:

  1. Join 操作:介紹如何使用 join 語法在兩個資料表之間進行聯結,並根據外鍵(如 CategoryId)取得相關資料。
  2. Navigation Properties:展示了如何使用 Entity Framework 的導航屬性,讓我們可以直接存取關聯的實體資料(如從 Product 查詢 Category)。
  3. Concurrency Model:講解並發衝突的概念,並示範如何透過例外處理來解決兩個使用者同時修改相同資料時可能產生的衝突。
  4. Multi-User Lab:演示如何模擬多使用者的操作環境,並通過資料庫隔離層級與資料鎖來控制資料的同步修改,確保資料一致性。

這些註釋讓每個功能點都能夠清晰展示,幫助學生理解各個功能在實際開發中的應用。

補充:XML

System.Xml.

System.Xml.XmlWriter