tags: PostgreSQL
#
紀錄在 Entity Framework Core(EF Core) 操作 PostgreSQL 資料庫的一些步驟和細節
- .NET 6
- PostgreSQL 15
- EF Core 7
前置作業#
想要透過 EF Core 存取資料庫,我們需要先到Nuget
上安裝對應的套件,也必須要有相對應的資料庫提供者也就是Provider
,透過引用不同的提供者讓 EF Core 可以存取不同的資料庫,在 Postgre 上我使用的提供者是 Npgsql.EntityFrameworkCore.PostgreSQL
以下是這是會用到的套件列表
1
2
3
4
5
6
7
| dotnet add package Microsoft.EntityFrameworkCore --version 7.0.4
dotnet add package Microsoft.EntityFrameworkCore.Abstractions --version 7.0.4
dotnet add package Microsoft.EntityFrameworkCore.Analyzers --version 7.0.4
dotnet add package Microsoft.EntityFrameworkCore.Design --version 7.0.4
dotnet add package Microsoft.EntityFrameworkCore.Relational --version 7.0.4
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 7.0.3
dotnet add package EFCore.NamingConventions --version 7.0.2
|
DbContext#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("Host=localhost;Database=efcoresample;Username=user;Password=password")
.UseSnakeCaseNamingConvention();
}
public class Blog
{
public int Id { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
|
這邊我使用官方文件上的範例來說明,要在C#和資料庫做溝通,我們需要建立一個類別並且繼承DbContext
,並且在其中利用DbSet
定義我們需要的資料表,Blog
Post
則是資料表的欄位定義模型也就是Entity
其中 OnConfiguring
方法,可以用來定義資料庫的連線字串,但更好的方法是從外部注入,做法是在 Program.cs
中加入以下的程式碼
1
2
3
4
| builder.Services.AddDbContext<BloggingContext>(
options => options
.UseNpgsql(Configuration.GetConnectionString("BloggingContext"))
.UseSnakeCaseNamingConvention());
|
其中的 BloggingContext
是連線字串的名稱,資料庫連線字串則是寫在 appsetting.json
內
1
2
3
4
5
6
| {
"ConnectionStrings": {
"BloggingContext":
"Host=localhost;Database=efcoresample;Username=user;Password=password"
},
}
|
UseSnakeCaseNamingConvention#
在C#的命名慣例上我們習慣使用駝峰式命名法(camel case),但在Postgresql
上的命名慣例則是蛇形命名法(snake case),如果我們沒有在DbContext
上指定命名慣例,Migration時會按照C#來慣例來為資料表命名
駝峰式命名法(camel case)#
單字之間不分開,又分成大駝峰(每一個單字首字大寫)、小駝峰(首字小寫後續單字首字大寫)
1
2
| 大駝峰 UseSnakeCaseNamingConvention
小駝峰 useSnakeCaseNamingConvention
|
蛇式命名法(snake case)#
單字與單字之間透過_
連接,單字首字皆為小寫
1
| use_snake_case_naming_convention
|
我覺得這個非常重要,我在剛接觸的時候沒有注意到命名的問題,再開發的時候使用pgAdmin
一直想說為什麼下SQL時資料表以及欄位名稱都要加""
,後來才知道命名會影響語法的格式
假設我的 Table 名稱是 BlogPost
1
| SELECT * FROM "BlogPost"
|
Table 名稱為 blog_post
1
| SELECT * FROM blog_post
|
OnModelCreating#
如果想要對資料庫做更加細部的設定,我們可以複寫 OnModelCreating
這個方法
屬性生成#
UseSerialColumns#
若主鍵欄位是數字並希望可以自動增加,下方的寫法可以做全域的的設定
1
2
| protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.UseSerialColumns();
|
Guid#
當主鍵是Guid時,Ef Core
的預設行爲是在客戶端產生Guid後送到資料庫,這邊用Blog
來舉例,它有一個欄位叫做BlogGuid
型別是Guid,需要在建立時自動的產生
1
2
3
4
| protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>()
.Property(b => b.BlogGuid)
.HasValueGenerator<GuidValueGenerator>();
|
就如預設的行為,這會在客戶端產生並且送入資料庫,若希望在資料庫內產生也是可以
1
2
3
4
5
6
7
| protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Blog>()
.Property(e => e.BlogGuid)
.HasDefaultValueSql("gen_random_uuid()");
}
|
這樣寫就會在資料庫呼叫gen_random_uuid
方法去產生Guid
索引 Index#
為了提升效能,索引是一個非常常用的方法,下面的語法是為Blog
資料表的url
欄位建立索引的寫法
1
2
| protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().HasIndex(x => x.Url);
|
如果想要使用postgresql 11
的include index
可以這樣寫
1
2
3
4
| protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>()
.HasIndex(x => x.Id)
.IncludeProperties(x => x.url);
|
執行移轉(Migration)#
當我們完成Entity
以及DbContext
的設定後,最後一步就是把我們的設定套用到資料庫上。
首先使用這行指令建立新的 migration
1
| dotnet ef migrations add InitialCreate
|
再使用下列語法套用資料庫的更新
1
| dotnet ef database update
|
完成後專案內會出現 Migrations
資料夾,並且Postgresql
內也會出現對應的資料庫以及資料表