---
# System prepended metadata

title: C#Database1Entities and DataTable
tags: [Database, DataTable, C#]

---

# C#Database1Entities and DataTable
兩者都是 C# 處理資料庫的方式，但本質與用途完全不同
| 名稱                | 類型                         | 用途                                    |
|---------------------|------------------------------|-----------------------------------------|
| Database1Entities    | EF (Entity Framework) 的 DbContext | 透過物件關聯對應 (ORM) 來存取資料庫       |
| DataTable            | ADO. NET 的資料表             | 以表格的方式存放資料，類似 Excel 的表格   |

[TOC]
## Database1Entities
用來管理 資料庫 的存取
💡 主要用來跟 SQL 資料庫 進行互動，並將資料映射成 C# 物件。

書寫的部分可以搭配[C#LINQ(微SQL)](/a6zrFWuFRs6g4ZJ8xn8vTw)來做參考
### 安裝 Entity Framework
打開 「NuGet 套件管理器」，在 Visual Studio 中，安裝 Entity Framework：
1. 工具 (Tools) → NuGet 套件管理員 (NuGet Package Manager) → 管理解決方案的 NuGet 套件
1. 搜尋 EntityFramework，點擊安裝

![image](https://hackmd.io/_uploads/r1GfxyghJl.png=50%)

### 💠實體化(ADO)與class
💡💡💡如果使用 ADO.NET，你需要執行 transaction.Commit();來進行儲存資料
(怪怪的...ADO如何在下次點擊開始時還保留資料?)

table的寫法只需要與實體化的寫法一樣，get,set
```csharp=
public partial class Table
{
    public string date { get; set; }
    public string who { get; set; }
    public string money { get; set; }
    public string pay { get; set; }
}

----------------------------------------------
程式寫法：
db.Table.RemoveRange(db.Table);  // 清空 Table 表
db.Table.AddRange(importData);
db.SaveChanges();  // 儲存變更
```
```csharp=
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;


public class Database1Entities : DbContext
{
    public DbSet<User> Users { get; set; } //資料表名稱不一定要 User
}

public partial class User
{
    [Key]  //標註主鍵
    public string 入住日期 { get; set; }
    public string 退房日期 { get; set; }
    public string 人數 { get; set; }
    public string 支付方式 { get; set; }
    public string 房型 { get; set; }

}
```
### 💠名稱問題
💡資料表名稱是否一定要 User？
✔️不一定！

User 類別 只是 C# 內的類別名稱
預設情況下，會將類別名稱轉為 Users 作為資料表名稱（因為 DbSet < User > 會自動轉為 Users）。

💠但如果你的資料庫名稱不是 Users，可以這樣設定：
```csharp=
[Table("你的資料表名稱")]
public partial class User
```
例：
```csharp=
[Table("顧客資料")]
public partial class User
```
這樣就會對應到 顧客資料 這張表，而不是 Users。

---
### 💠不建議使用中文
你的 User 類別屬性名稱是 入住日期、退房日期 等中文，雖然 C# 支援中文變數，但不建議這樣做，因為：
* 可能會導致某些程式碼難以維護。
* 可能會有 資料庫映射問題。
* 在 LINQ 查詢 時可能會有編譯問題。
✅ 修正方式（使用英文命名並設定映射）：

```csharp=
[Table("顧客資料")]
public partial class User
{
    [Key]
    [Column("入住日期")]
    public string CheckInDate { get; set; }

    [Column("退房日期")]
    public string CheckOutDate { get; set; }

    [Column("人數")]
    public string NumberOfPeople { get; set; }

    [Column("支付方式")]
    public string PaymentMethod { get; set; }

    [Column("房型")]
    public string RoomType { get; set; }
}
```
這樣：
程式碼保持英文可讀性。
[Column("原本資料庫欄位名稱")] 讓 EF 對應到原本的資料庫欄位，不用改資料庫名稱。
### 💠DbContext 連結字串(?
DbContext 應該要有建構函式
你的 Database1Entities 繼承了 DbContext，但沒有設定 資料庫連線字串，應該這樣改：

```csharp=
public class Database1Entities : DbContext
{
    public Database1Entities() : base("name=你的連線字串名稱") { }

    public DbSet<Reservation> Reservations { get; set; }
}
```
這樣才會連接到 App.config / Web.config 的資料庫設定。
### 基本結構
```csharp=
using (Database1Entities db = new Database1Entities())  //// 創建資料庫連線
{
    var users = db.Users.ToList();  // 取得 Users 資料表的所有資料
    foreach (var user in users)
    {
        Console.WriteLine(user.Name);
    }
}//程式結束時會釋放資料庫連線，避免連線資源占用
```

* db.Users 是 Users 資料表的 ORM 物件，透過 .ToList() 抓取所有資料。
* EF 會自動轉換 SQL 查詢，讓我們直接操作 C# 物件，而不用寫 SQL 語法。

###  查詢 LINQ
🔹取得所有資料
```csharp=
var data = db.Table1.ToList();
```
🔹 取得符合條件的資料
```csharp=
var result = db.Table1.Where(x => x.Name == "John").ToList();
```
🔹 取得單筆資料
FirstOrDefault() 只會回傳 第一筆符合條件的資料，如果沒有資料，會回傳 null。
```csharp=
var person = db.Table1.FirstOrDefault(x => x.Id == 1);
if (person != null)
{
    Console.WriteLine($"找到使用者：{person.Name}");
}
```
### 查詢2 Find
根據主鍵（Primary Key）查找資料。
```csharp=
var user = db.Users.Find(1);
```
📌 這會在 Users 資料表中，尋找 Id = 1 的使用者
📌 Find 只適用於主鍵查找，不能查其他欄位
如果資料庫內 Id = 1 存在，***則 user 會是一個 User 物件***；
如果沒有找到，則 user 會是 null。

💠如果 Users 表有複合主鍵
```csharp=
var order = db.Orders.Find(1, "A123");
```
📌 這裡 Find(1, "A123") 會依序對應到 Id 和 OrderCode 兩個主鍵

💠非主鍵查詢
```csharp=
var user = db.Users.FirstOrDefault(u => u.Email == "test@example.com");
```
### 查詢3 似LIKE
1️⃣ 使用 Contains、StartsWith、EndsWith
在 EF LINQ 查詢中，LIKE 對應的方法有：
* Contains() 等同於 LIKE '%值%'
* StartsWith() 等同於 LIKE '值%'
* EndsWith() 等同於 LIKE '%值'

📌 範例：查詢名稱包含 "John" 的用戶
```csharp=
using (var db = new DatabaseContext())
{
    var users = db.Users.Where(u => u.Name.Contains("John")).ToList();
}
```
📌 查詢以 "J" 開頭的用戶
```csharp=
var users = db.Users.Where(u => u.Name.StartsWith("J")).ToList();
```
📌 查詢以 "son" 結尾的用戶
```csharp=
var users = db.Users.Where(u => u.Name.EndsWith("son")).ToList();
```

---
原生態LIKE使用：
```csharp=
var users = db.Users.Where(u => EF.Functions.Like(u.Name, "%John%")).ToList();
```
### 檢查是否存在
* Any
有時我們只需要確認資料是否存在，而不需要真的查詢：
```csharp=
// 檢查是否有名稱為 Alice 的使用者
bool exists = db.Users.Any(x => x.Name == "Alice"); 
```
* Find
使用是否為null來判斷
```csharp=
var user = db.Users.Find(1);
if (user != null){}
```
###  使用 Where 篩選
```csharp=
var users = db.Users.Where(u => u.Age > 20).ToList();
```
📌 Where 讓你篩選符合條件的資料。
### 取得所有資料
```csharp=
var users = db.Users.ToList();  // 取得 Users 資料表的所有資料
foreach (var user in users)
{
    Console.WriteLine($"ID: {user.Id}, Name: {user.UserName}");
}
```
ToList() 會把 Users 表內所有資料讀取到 List 裡。
```csharp=
foreach (var item in db.Users)
{
    listBox1.Items.Add($"{item.入住日期}-{item.退房日期}-{item.人數} 付現：{item.支付方式} {item.房型}");
}
```
### 計算筆數	
```csharp=
db.Users.Count()
```
### 新增 
```csharp=
using (Database1Entities db = new Database1Entities())
{
    Table1 newPerson = new Table1()
    {
        Id = 3,
        Name = "Alice",
        Age = 22
    };

    db.Table1.Add(newPerson); // 加入資料
    db.SaveChanges(); // 儲存變更到資料庫
}
```
```csharp=
using (var db = new Database1Entities())
{
    var user = new User()
    {
        入住日期 = dateTimePicker1.Value.ToString("yyyy年MM月dd日"),
        退房日期 = dateTimePicker2.Value.ToString("yyyy年MM月dd日"),
        人數 = comboBox1.Text,
        支付方式 = radioButton1.Checked ? "是" : "否",
        房型 = comboBox2.Text
    };
    db.Users.Add(user);
    db.SaveChanges();
}
```
### 修改 
```csharp=
using (Database1Entities db = new Database1Entities())
{
    var person = db.Table1.FirstOrDefault(x => x.Id == 3);
    if (person != null)
    {
        person.Name = "Alice Updated"; // 修改名稱
        db.SaveChanges(); // 儲存變更
    }
}
```
### 刪除
```csharp=
using (Database1Entities db = new Database1Entities())
{
    var person = db.Table1.FirstOrDefault(x => x.Id == 3);
    if (person != null)
    {
        db.Table1.Remove(person); // 刪除資料
        db.SaveChanges(); // 儲存變更
    }
}
```
### 清空
```csharp=
db.Table.RemoveRange(db.Table);  // 清空 Table 表
```
db.Tables.RemoveRange 是 Entity Framework（EF） 中用來批量刪除資料庫資料的方法。
### OrderBy 

----
### 升序、降序 OrderBy,OrderByDescending
* 升序
```csharp=
var result = database1Entities.table.OrderBy(x => x.Id).ToList();
```
* 降序
```csharp=
var result = database1Entities.table.OrderByDescending(x => x.Age).ToList();
```
### 取出排序後的前 5 筆資料
這樣可以取出年齡最小的前 5 筆資料。
```csharp=
var top5 = database1Entities.table.OrderBy(x => x.Age).Take(5).ToList();
```
### 取出 Age 大於 25 並排序
這樣可以 先篩選出 Age > 25 的資料，再按照 Name 排序。
```csharp=
var result = database1Entities.table
    .Where(x => x.Age > 25)
    .OrderBy(x => x.Name)
    .ToList();
```
| 方法                           | 作用                  |
|--------------------------------|-----------------------|
| OrderBy(x => x.欄位)          | 升序排序 （小 → 大）   |
| OrderByDescending(x => x.欄位) | 降序排序 （大 → 小）   |
| ThenBy(x => x.欄位)           | 第二個條件升序排序     |
| ThenByDescending(x => x.欄位)  | 第二個條件降序排序     |
| Take(n)                        | 取前 n 筆資料         |
| Skip(n)                        | 跳過前 n 筆資料       |

----
### 分頁Take(n) 和 Skip(n)
分頁是用來 限制查詢結果的數量，通常搭配 Take(n) 和 Skip(n) 使用。
```csharp=
int pageSize = 10; // 每頁顯示 10 筆
int pageNumber = 2; // 取得第 2 頁的資料

var pagedUsers = db.Users
    .OrderBy(x => x.Id)
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToList();
```
這樣就會 從第 11 筆開始，取 10 筆資料。
* Skip(n)：跳過前 n 筆資料。
* Take(m)：從目前查詢的結果中，取出最多 m 筆資料。

### 最大值、最小值
```csharp=
var maxAge = db.Users.Max(x => x.Age); // 取得最大年齡
var minAge = db.Users.Min(x => x.Age); // 取得最小年齡
var avgAge = db.Users.Average(x => x.Age); // 取得年齡平均值
```
### 執行 SQL	
```csharp=
db.Users.FromSqlRaw("SELECT * FROM Users").ToList()
```
### 💡使用 Code First Migrations
[C# Migration 管理資料庫結構變更](/e7FdOBEkQwevbmEGSHBIxw)這裡有一些相關介紹
這是最好的方式，可以讓你更新資料庫結構而不會刪除舊資料。

1️⃣ 打開 Visual Studio 的「套件管理員主控台」（Package Manager Console）
（工具 -> NuGet 套件管理員 -> 套件管理員主控台）

2️⃣ 啟用 Migrations 在 套件管理員主控台 輸入：

```pgsql=
Enable-Migrations
```
⚡ 這會在專案中建立 Migrations 資料夾，並產生 Configuration.cs

3️⃣ 產生遷移（同步 Model 和 Database）

```sql=
Add-Migration InitialCreate
-------------------------------
Add-Migration 名稱
```
🚀 這會建立一個 InitialCreate 檔案，記錄變更

4️⃣ 更新資料庫

```pgsql=
Update-Database
```
📌 這步驟會將 C# Model 更新到資料庫，不會刪除舊資料。

### TransactionScope 確認儲存
```csharp=
using (var scope = new TransactionScope())
{
    using (var db = new Database1Entities())
    {
        var user = new User()
        {
            入住日期 = dateTimePicker1.Value.ToString("yyyy年MM月dd日"),
            退房日期 = dateTimePicker2.Value.ToString("yyyy年MM月dd日"),
            人數 = comboBox1.Text,
            支付方式 = radioButton1.Checked ? "是" : "否",
            房型 = comboBox2.Text
        };
        db.Users.Add(user);
        db.SaveChanges();
    }
    scope.Complete(); // 只有所有操作成功，才會真正儲存
}
```
### 交易處理 Transaction
如果你有多個資料庫操作，需要確保 所有步驟都成功才提交變更，可以使用 Transaction。
```csharp=
using (var transaction = db.Database.BeginTransaction())
{
    try
    {
        var user = new User { Name = "Bob", Age = 20 };
        db.Users.Add(user);
        db.SaveChanges();

        var user2 = db.Users.FirstOrDefault(x => x.Id == 2);
        if (user2 != null)
        {
            user2.Name = "Updated Name";
            db.SaveChanges();
        }

        transaction.Commit(); // 成功後提交
    }
    catch (Exception)
    {
        transaction.Rollback(); // 發生錯誤時回滾
    }
}
```
### 關聯查詢 (Join)
假設 Users 和 Orders 之間有關聯 (UserId)，可以用 Join 來查詢：
```csharp=
var userOrders = db.Users
    .Join(db.Orders,
        user => user.Id,
        order => order.UserId,
        (user, order) => new 
        { 
            UserName = user.Name, 
            OrderAmount = order.Amount 
        })
    .ToList();
```

## DataTable 
ADO. NET 提供的一種 記憶體內的資料表格，用來儲存查詢結果，類似 Excel 的表格
💡 DataTable 主要用於 離線存取資料，不依賴 ORM。
```csharp=
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));       // 新增欄位 ID
dt.Columns.Add("Name", typeof(string));  // 新增欄位 Name

// 新增一筆資料
dt.Rows.Add(1, "Alice");
dt.Rows.Add(2, "Bob");

// 讀取 DataTable
foreach (DataRow row in dt.Rows)
{
    Console.WriteLine($"{row["ID"]}: {row["Name"]}");
}
```
* dt.Columns.Add() → 新增欄位
* dt.Rows.Add() → 新增資料
* dt.Rows → 讀取資料

## 差異總結
| 特性               | Database1Entities (Entity Framework) | DataTable (ADO. NET) |
|--------------------|--------------------------------------|----------------------|
| 性質               | ORM (物件關聯對應)                   | 表格型資料結構       |
| 存取方式           | 使用 Linq 查詢 (db.Table1.Where(x => x.Id == 1)) | 使用 迴圈搜尋 (DataTable.Select())    |
| 綁定 DataGridView  | dataGridView.DataSource = db.Table1.ToList();   | dataGridView.DataSource = dt;         |
| SQL 操作           | 自動產生 SQL 查詢 (Linq)            | 需要手動寫 SQL       |
| 離線存取           | ❌ 需要連線資料庫                    | ✅ 可以存放在記憶體，不需連線 |
| 使用場景           | 大多數企業級應用程式，適合大規模資料存取 | 小型應用程式，或是當作暫存表 |

* 如果你使用 Entity Framework (ORM)，就用 Database1Entities
* 如果只是暫存資料、需要離線存取，可以使用 DataTable
* 如果要操作大量 SQL、效能需求高，可以使用 ADO. NET (DataTable + SqlCommand)

## 使用時機
#### 直接載入 DataGridView：
```csharp=
using (Database1Entities db = new Database1Entities())
{
    dataGridView1.DataSource = db.Table1.ToList();  // 直接載入資料
}
```
📌 優點：
* 程式碼簡單，直接從資料庫讀取並顯示。

📌 缺點：
* 無法輕鬆修改資料（例如，你要調整 DataGridView 的資料格式）。
* 資料無法脫離資料庫使用（需要 Database1Entities 存取）。
* 不能使用篩選、排序，如果 Table1 資料很多，載入時會影響效能。

#### 透過 DataTable 載入
如果你使用 DataTable，你可以先讀取資料，然後再顯示在 DataGridView
📌 優點：
1. 可以脫離資料庫操作（你可以用 DataTable 存資料，不必連線資料庫）。
1. 可修改資料後再寫回資料庫（你可以先修改 DataTable，確認後再存）。
1. 提供更多彈性：
* 你可以調整欄位名稱。
* 只選取部分欄位，而不會一次抓全部資料。
* 加強效能，避免每次都直接查詢資料庫。
    
📌 缺點：
* 需要額外的記憶體來存 DataTable。
* 程式碼較長。

| 使用情境                           | 選擇方式                                 |
| ---------------------------------- | ---------------------------------------- |
| 只需要顯示資料，不修改、不篩選     | 直接綁定 DataGridView (db.Table1.ToList()) |
| 需要在 UI 進行篩選、排序或修改     | 使用 DataTable                           |
| 資料來源不只是資料庫（例如 API、CSV）| 使用 DataTable                           |
| 想避免頻繁查詢資料庫               | 使用 DataTable                           |
    
如果只是顯示資料，直接綁定 DataGridView 是最簡單的方法。但如果你想 修改資料、篩選、排序，或避免頻繁存取資料庫，使用 DataTable 會更好！
    
## Database1Entities with DataTable
Entity Framework 會回傳 List<T> 或 IQueryable<T>，但 DataGridView 需要的是 DataTable，所以我們要轉換。
```csharp=
using (Database1Entities db = new Database1Entities())  // 建立資料庫連線
{
    DataTable dt = new DataTable();  // 建立 DataTable
    dt.Columns.Add("ID");
    dt.Columns.Add("Name");
    dt.Columns.Add("Age");
    // 查詢資料
    var query = db.Table1.Select(t => new { t.Id, t.Name, t.Age }).ToList(); 

    foreach (var item in query)
    {
        dt.Rows.Add(item.Id, item.Name, item.Age);  // 加入 DataTable
    }
    dataGridView1.DataSource = dt;  // 綁定到 DataGridView 顯示
}
```