# 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,點擊安裝

### 💠實體化(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 顯示
}
```