比起Datebase First,Code First要在vs這邊做的作業就比較多了
主要原因就是把本來在SQL Server 上建立資料表的動作,移到了程式這邊來做
那本課程的範例檔資料庫,也會是使用Code First方式來實作
主要是上一個課程雖然有提供mdf檔,讓大家可以正常的運作範例檔
但後來發現,mdf檔也有版本,會因為大家的環境不一樣,還需要做很多調整
所以這次改成用Code First的方式,資料庫環境由大家自己準備,範例檔需要的相關資料表就由Code First方式寫回去
這樣就比較不會有範例檔執行上的問題
本課程使用SQL Server當作資料庫,如果要跟著課程做但不會的,這邊有基本教學SQL Server安裝教學及設定TCP/IP教學和SQL Server Management Studio基本操作
Code First雖然一切都在vs這邊打好程式碼,盡量不碰到資料庫
但首先我們還是要先把資料庫環境先建立一開頭,不然沒有資料庫環境,也就沒有地方給我們將code的內容回寫建立相關資料庫
那我這邊使用的是SQL Server,我就先建立好了一個Kcg的資料庫和Kcg的登入帳號
當然還是有方法不用的,就是你使用的是系統管理員的帳號就可以完全不用進來這邊先設定,但實際開發上應該是不會這樣做
那首先要使用Code First,需要先安裝以下二個套件:
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
到方案總管的相依性>套件>管理NuGet套件
到上圖的導覽搜尋上面幾個套件然後進行安裝
接著開始建立你想要的資料表欄位
我們建立一個Models的資料夾,並在下面新增一個類別,這是對應你資料庫的資料表檔案
假使我們有一個資料表要取名為TOPMenu,那我們就建立一個TOPMenu的class
接著在裡面打上對應的欄位名稱
namespace Kcg.Models;
public partial class TOPMenu
{
public Guid TOPMenuId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Icon { get; set; }
public int Orders { get; set; }
}
接著在建立一個資料庫物件檔KcgContext.cs,那這邊可以依照你的資料庫名稱取名
裡面我們先打上以下內容
public partial class KcgContext : DbContext
{
public KcgContext(DbContextOptions<KcgContext> options) : base(options)
{
}
public DbSet<TOPMenu> TOPMenu { get; set; }
}
接著我們再到appsettings.json寫上我們設定好的連線字串
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"KcgDatabase": "Server=127.0.0.1;Database=Kcg;User ID=Kcg;Password=123456;TrustServerCertificate=true"
}
}
然後我們在Program.cs
中加入資料庫物件的DI注入(這以後會講,這邊先這樣照做)。
builder.Services.AddDbContext<KcgContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("KcgDatabase")));
其中Configuration.GetConnectionString("KcgContext")
可以從appsettings.json
中抓出"WebDatabase:"後面的內容,這部分就是說,請把一些參數的東西寫在appsettings.json
裡,然後再用Configuration.GetConnectionString
去抓取,而不要直接把連線字串寫死在程式裡,在日後維護或安全的考量上會較為良好。
接著我們就可以下指令來準備先建立一個有點類似紀錄你資料庫資料表中變化的紀錄檔的東西
Add-Migration InitialCreate
執行完後就會多一個Migrations資料夾,裡面放的就是準備回寫至資料的程式碼,跟以後修改的歷程記錄
接著我們在下一個指令
Update-Database
成功之後我們回到我們的資料庫看
就會看到TOPMenu的資料表被建好了,還有另一個是Code First的紀錄資料表
不過這時候我們點進去看資料表的欄位
雖然欄位名稱都跟我們建的類別檔內容一樣,但似乎哪裡可能還需要做調整
沒錯,資料類型可能不見得是我們要的,譬如我這邊不想要長度是MAX
那我們就要回頭到KcgContext.cs增加一些東西,畢竟你不告訴它你要什麼,它怎麼會知道
所以再加上以下程式碼
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TOPMenu>(entity =>
{
entity.Property(e => e.TOPMenuId).HasDefaultValueSql("(newid())");
entity.Property(e => e.Icon).IsRequired().HasMaxLength(50);
entity.Property(e => e.Name).IsRequired().HasMaxLength(50);
entity.Property(e => e.Url).IsRequired().HasMaxLength(50);
entity.Property(e => e.Orders).IsRequired();
});
}
這邊我想要讓主鍵可以自動產生Id所以下了一個sql函式newid()
接著就是個欄位的長度50就好,然後不可以為空.IsRequired()
加完之後我們要紀錄一下,我的表格有做更新
Add-Migration TOPMenuUp
這邊Add-Migration後面的英文式自己取的一個紀錄名稱,那我這邊要更新TOPMenu所以叫TOPMenuUp
成功之後就會多一個紀錄檔
接著在執行更新資料庫指令
Update-Database
成功之後我們在回到資料庫看看,應該都會進行修正成我們要的了
以上就是Code First基本的操作
看起來好像麻煩不少,那主要的原因是因為把本來在資料庫裡設計的工作,都轉成在程式這邊設計了
也就是多了一份資料庫設計的工作要做,但是是用Code來做
那這樣的好處是什麼?
大概就是能不用開啟資料庫環境,直接在vs2022上改完code,資料庫環境也跟著修改
你就不用開著兩邊修改,而我們也只要學會怎麼用code寫資料庫,而不用去學資料庫怎麼操作
其實微軟一直有在各方面做把事情單一化的功能,就是你只要學一個東西,就可以使用到各個不同的地方
但好不好用就見仁見智了XD
最後我們要來測試連線資料庫把資料取出來,但是目前沒有資料可以取,我們也不碰SSMS新增資料怎麼辦
這邊可以在程式中設定預設資料,當某個資料表中如果沒有資料,我們就先新增一些資料進去
這種作法其實很有用處,假設你有關鍵資料是必須存在資料表中程式才能順利啟動,那就可以加上這段,避免以後移機時可能發生的錯誤
我們再回到KcgContext.cs增加一些東西
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TOPMenu>().HasData(
new TOPMenu { Name = "網站導覽", Url = "a1", Icon = "Icon1", Orders = 1 },
new TOPMenu { Name = "回首頁", Url = "a2", Icon = "Icon2", Orders = 2 },
new TOPMenu { Name = "English", Url = "a3", Icon = "Icon3", Orders = 3 },
new TOPMenu { Name = "雙語詞彙", Url = "a4", Icon = "Icon4", Orders = 4 },
new TOPMenu { Name = "市長信箱", Url = "a5", Icon = "Icon5", Orders = 5 },
new TOPMenu { Name = "洽公導覽", Url = "a6", Icon = "Icon6", Orders = 6 });
modelBuilder.Entity<TOPMenu>(entity =>
{
entity.Property(e => e.TOPMenuId).HasDefaultValueSql("(newid())");
entity.Property(e => e.Icon).IsRequired().HasMaxLength(50);
entity.Property(e => e.Name).IsRequired().HasMaxLength(50);
entity.Property(e => e.Url).IsRequired().HasMaxLength(50);
entity.Property(e => e.Orders).IsRequired();
});
}
這樣如果表格中沒有資料,就會增加資料這些預設資料進去,當然我們要再次做一下紀錄變更
Add-Migration AddData
接著再把資料更新到資料庫裡
Update-Database
我們可以回去SQL Server看一下,資料有沒有正確新增上去
這樣就代表設定是沒問題的
接著開始準備取出資料,先到HomeController.cs中寫下以下程式
private readonly KcgContext _kcgContext; //先在全域宣告資料庫物件
public HomeController(KcgContext kcgContext) //這邊是依賴注入使用我們剛設定好的資料庫物件的寫法
{
_kcgContext = kcgContext;
}
如果之前有寫過C#跟資料庫連線但沒用過依賴注入的人,可能會覺得很特殊,以前使用宣告資料庫可能會是這樣寫的
using (var _kcgContext = new KcgContext())
{
}
但這要自己管理好生命週期,且更有新手可能連using都不會用,因而時不時有人就踩坑讓系統爆炸
現在用的這種叫依賴注入的寫法,由程式自動幫你管理好生命週期,你儘管用不需要擔心會採什麼坑
所以既然都來到的.NET Core時代,就改用依賴注入的寫法吧
為什麼我特別這麼說,因為發現還是很多人都轉來.NET Core了,還是放不下以前的寫法,其實這並沒有很難
最後我們在這邊簡單寫一下回傳TOPMenu資料表的資料,如下
public string Index()
{
return _kcgContext.TOPMenu.FirstOrDefault().Name;
}
按下啟動不偵錯查看結果
可以看到網頁上就有"English"是我們剛剛新增的其中一筆被我們從資料庫撈出來了
以上就是從資料庫撈資料的事前設定
跟在Controller中要如何使用資料庫物件撈取資料
不過看到這邊,應該有很多人不想用Code First了,沒關係,選擇你喜歡的開發方式就可以了
那這邊順帶一提,可能有人會跟我剛接觸Code First時有個疑問
就是這是在開發環境可以這樣做,那我在正式環境的時候,難道要用vs去連正式環境的資料庫去做資料庫更新嗎?
當然不是,其實跟你原來的做法一樣就好
就算是用Database First你先在開發環境建好資料庫,到時候到了正式環境,你可能是用匯出SQL,或精靈方式
把開發環境的資料庫建到正式環境,或給DBA相關更新SQL指令,請他更新上去
那在Code First也是一樣的作法,你只是在開發環境用Code First建好開發環境的資料表
但之後你一樣是從SQL Server去匯出相關更新SQL,或精靈匯出,之後再帶到正式環境去更新
差別只差在Database First是你自己在SQL Server上建資料表,而Code First是指令工具幫你建的
最後開發環境上都會有一個跟你程式相符的資料庫內容
然後你再用你原本怎麼移轉到正式環境的方式即可
不需要一定要用Code First的工具建的才能夠運作,資料庫裡的資料表結構都一樣即可