---
# System prepended metadata

title: 使用Entity Framework建立資料庫

---


{%hackmd BJrTq20hE %}

<style>
    .markdown-body:not(.next-editor) pre {
    padding: 16px;
    background-color: #333;
}
    .markdown-body pre.flow-chart, .markdown-body pre.sequence-diagram, .markdown-body pre.graphviz, .markdown-body pre.mermaid, .markdown-body pre.abc {

background-color:  #d9edf7 !important;<!-mermaidbg-!>
    }
    .markdown-body {

font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
padding-top: 40px;
padding-bottom: 40px;
max-width: 800px; <!-筆記寬度-!>
overflow:  visible !important;
position: relative;

}
</style>
## SSMS建立資料庫
1. 首先在開啟SSMS並新增一個資料庫
![image](https://hackmd.io/_uploads/rJ2DCE3Hp.png)
2. 新增一個使用者，這邊建議使用sql認證
![image](https://hackmd.io/_uploads/HkwZJBhB6.png =40%x)
![image](https://hackmd.io/_uploads/BJurJHnB6.png)
3. 對新增的登入角色右鍵&rarr;屬性來賦予使用者權限
![image](https://hackmd.io/_uploads/rJq01HnBT.png =40%x)
![image](https://hackmd.io/_uploads/rJFrgS3Sp.png)

4. 並在安全性實體的地方給予他改變資料庫和建立資料庫權限(待確認是否需要)
![image](https://hackmd.io/_uploads/SJogWrnS6.png)
5. 確定一下資料庫是否有加入使用者
![image](https://hackmd.io/_uploads/ryPNbB3Hp.png =40%x)

## Entity Framework建立codeFirst資料表(使用MVC範例)

1. 選擇工具&rarr;Nuget套件管理員&rarr;管理方案的Buget套件
![image](https://hackmd.io/_uploads/B1f3GS3rT.png)
2. 檢查是否有安裝EntityFramework，如果沒有就需要安裝
![image](https://hackmd.io/_uploads/Ska3XH2ra.png)
3. 由於資料表建立在Model中，因此我們需要在Model新建資料表，Model&rarr;加入&rarr;新增項目
![image](https://hackmd.io/_uploads/r18X4H2rp.png)
4. 選擇ADO.NET實體資料模型這邊範例名稱為Context
![image](https://hackmd.io/_uploads/ryt_EB2r6.png)
5. 選擇來自資料庫的CodeFirst
![image](https://hackmd.io/_uploads/rkdJBS3Sp.png)
6. 輸入自己的伺服器名稱，輸入剛才的驗證資訊，(VS2022新版EF加密可以先使用False，VS19及舊版EF 5.X.X 沒有這個選項)
![image](https://hackmd.io/_uploads/r1GwSrnB6.png)

:::info
**伺服器名稱是什麼?**
SSMS就是登入時所使用的伺服器名稱，通常會在登入時看見，直接複製貼上就好囉
![image](https://hackmd.io/_uploads/SJLzBHhST.png =40%x)
:::
7. 選擇"是，再連接字串中包含敏感性資料"，下一步
![image](https://hackmd.io/_uploads/Sk498r3Sa.png)
8. 因為沒有建立任何資料表因此都不用選擇
![image](https://hackmd.io/_uploads/HJ2yDB3Sa.png)
9. 建立成功
![image](https://hackmd.io/_uploads/ByOGvr3Ba.png)
10. 可以在webConfig確定相關資訊是否在connectionstring中
![image](https://hackmd.io/_uploads/H1I_vr3HT.png)

11. 接下來就是在Nuget套件主控台輸入指令`Enable-Migrations`
![image](https://hackmd.io/_uploads/r1-4VI2rp.png)


## Migrations

&emsp;&emsp;在 .NET 開發中，使用 Entity Framework (EF) 建立資料表後，啟動 Migrations 的主要目的是管理資料庫結構的變化。Migrations 提供以下功能：

1.  **版本控制**：Migrations 讓你能夠對資料庫結構的更改進行版本控制，這樣你就可以追蹤隨時間發生的所有變更。
    
2.  **更新資料庫結構**：當你的模型類別（Entity classes）發生更改時，你可以使用 Migrations 來更新資料庫結構，使其與模型保持一致。
    
3.  **逐步遷移**：Migrations 允許你逐步對資料庫進行更改。你可以一步一步地應用或回退更改，而不需要重建整個資料庫。
    
4.  **自動化腳本生成**：EF Migrations 可以自動產生 SQL 腳本，這些腳本可用於將更改部署到生產資料庫。
    
5.  **跨環境一致性**：通過使用 Migrations，你可以確保所有開發、測試和生產環境中的資料庫結構保持一致。
    
6.  **數據種子（Seeding）**：Migrations 還可以用於資料庫的數據種子，即在資料庫創建或更新時自動填充數據。

**接下來要在資料庫中新建一個資料表，在Model新增一個類別，名為Org，組織與Member(成員)是一對多的情況(一個組織可以有很多成員)**

![image](https://hackmd.io/_uploads/B1LimU2Ha.png)


```csharp!
 public class Org
 {
     [Key]//主鍵PK
     [Display(Name = "編號")]//呈現欄位的名稱
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]//識別規格
     public int Id { get; set; }

     //[Required(ErrorMessage = "{0}必填")]//必填，驗證畫面呈現單位名稱必填
     [Required]//必填
     [MaxLength(100)]//=nvarchar(100)；沒寫=nvarchar(max)
     [Display(Name = "單位名稱")]
     public string Name { get; set; }

     [Required(ErrorMessage = "{0}必填")]
     [Display(Name = "發佈時間")]
     [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]//進行編輯操作時能夠看到適當格式的日期時間
     [DataType(DataType.DateTime)]//送出時驗證是不是時間格式
     public DateTime InitDate { get; set; }

     [Display(Name = "單位成員")]
     public virtual ICollection<Member> Members { get; set; }
 }
```

**解釋一下Org中的語法結構，這邊的一個屬性也就代表資料表中的一個資料表欄位**

*  **Id 屬性**：
    
    -   `[Key]`：標示這個屬性為主鍵 (Primary Key, PK)。
    -   `[Display(Name = "編號")]`：指定在 UI 中顯示的名稱為 "編號"。
    -   `[DatabaseGenerated(DatabaseGeneratedOption.Identity)]`：指定這個欄位在資料庫中是自動生成的識別欄位（通常是自增主鍵）。
*  **Name 屬性**：
    
    -   `[Required]`：表示這個欄位在資料庫中是必填的。
    -   `[MaxLength(100)]`：設定最大長度為 100 個字符，對應於資料庫中的 `nvarchar(100)`。
    -   `[Display(Name = "單位名稱")]`：指定在 UI 中顯示的名稱為 "單位名稱"。
*  **InitDate 屬性**：
    
    -   `[Required(ErrorMessage = "{0}必填")]`：表示這個欄位在資料庫中是必填的，如果未填寫，則顯示錯誤訊息 "{0}必填"。
    -   `[Display(Name = "發佈時間")]`：指定在 UI 中顯示的名稱為 "發佈時間"。
    -   `[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]`：設定在編輯模式下的日期格式。
    -   `[DataType(DataType.DateTime)]`：指定這個欄位的數據類型為日期時間。
*  **Members 屬性**：
    
    -   `[Display(Name = "單位成員")]`：指定在 UI 中顯示的名稱為 "單位成員"。
    -   `public virtual ICollection<Member> Members { get; set; }`：表示 `Org` 與 `Member` 之間的一對多關係。這裡使用 `virtual` 關鍵字來啟用 Entity Framework 的延遲加載功能。

:::danger
**這邊由於Member資料表尚未生成，所以應該要先註解掉才不會在add-migration發生問題**
:::

7. 接下來要將自己所新增的Org資料表放到Context.cs檔案

`public virtual DbSet<Org> Orgs { get; set; }`

```csharp!
    public partial class Context : DbContext
    {
        public Context()
            : base("name=Context")
        {
        }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }
        public virtual DbSet<Org> Orgs { get; set; }
    }
```
8. 在Nuget中輸入`add-migration '異動項目'`，`ex:Add-Migration 'initOrg'`
9. `Update-Database`更新資料庫，並確認是否有添加成功

![image](https://hackmd.io/_uploads/BJo4cPhST.png)


### 補充
在 Entity Framework (EF) 中，建立完資料表後，在 DbContext 中使用 DbSet 來記錄自己的資料表是出於以下幾個重要原因：

*  **映射到資料表**：DbSet 提供了一種方式來將你的實體類別（如 `Org`）映射到資料庫中的一個資料表。每一個 DbSet 屬性代表一個資料表中的集合，允許你對這個資料表進行查詢和保存操作。
    
*  **查詢操作**：DbSet 提供了一個方便的方式來查詢資料庫。使用 LINQ 查詢語句，你可以輕鬆地從資料庫中檢索數據，並且這些查詢會被轉換成對應的 SQL 查詢。
    
*  **CRUD 操作**：DbSet 也用於執行創建（Create）、讀取（Read）、更新（Update）和刪除（Delete）操作。當你對 DbSet 中的數據進行修改並調用 DbContext 的 SaveChanges 方法時，這些更改會自動反映到資料庫中。
    
*  **追蹤實體狀態**：Entity Framework 使用 DbContext 來追蹤實體的狀態（如新增、修改或刪除）。這使得數據的持久化（即保存到資料庫）變得容易和直觀。
    
*  **延遲加載**：當使用 DbSet 屬性時，EF 支持延遲加載（Lazy Loading）。這意味著實體的相關數據（例如，Org 實體中的 Members 集合）只有在真正需要時才從資料庫加載，這有助於提高性能。
    
*  **維護方便**：在 DbContext 中定義 DbSet 使得你的數據模型和操作集中管理，這對於維護和理解代碼非常有幫助。


## 添加Controller
1. 在Controllers&rarr;加入&rarr;控制器
![image](https://hackmd.io/_uploads/S1gL2UeUp.png)
2. 因為是MVC示範，所以選擇"具有檢視、使用Entity Framework的MVC控制器"
![image](https://hackmd.io/_uploads/BJR9h8gUa.png)
3. 選擇對應的模型類別、資料內容類別
![image](https://hackmd.io/_uploads/rJNgALl86.png)
4. 由於是MVC，且在控制器中有產生檢視，因此就會生成Views資料夾，同時也會生成Orgs資料夾(含Creat.cshtml、Delete.cshtml、Details.cshtml、Edit.cshtml、Index.cshtml)代表MVC本身幫我們自動生成了CRUD的功能
![image](https://hackmd.io/_uploads/HkCKrweUT.png)
5. 可以檢視一下Org的Create頁面，可以發現日期用輸入的方式，不直覺
![image](https://hackmd.io/_uploads/SJ2xLDlLT.png)
6. 我們可以在Create的程式碼中增加一個`type = "date"`讓他變成日曆的方式
![image](https://hackmd.io/_uploads/HkpO8Dg8p.png)

```htmlmixed
        <div class="form-group">
            @Html.LabelFor(model => model.InitDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.InitDate, new { htmlAttributes = new { @class = "form-control", type = "date" } })
                @Html.ValidationMessageFor(model => model.InitDate, "", new { @class = "text-danger" })
            </div>
        </div>
```



