EF Core 使用 PostgreSQL Jsonb 型別

Posted on 2018-12-26

前面的文章有大概介紹了 PostgreSQL Json 和 Jsonb 的不同,現在要來看如何在 EF Core 裡面使用 Jsonb

EF Core 2.2

PostgreSQL

  • 有一個 data 的 Table,typeuserjsonb

欄位名叫 user 會跟內建的 user 相衝,在實務上使用的話應該避免

使用 string 對應

  • DbContext 裡面的 OnModelCreating,去作 mapping
    • 因為 PostgreSQL 預設都是小寫,所以把 Table 和 Column 都先 mapping 成小寫
    • 然後把 2 個 Column mapping 成 jsonb
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Data>(build =>
    {
        build.ToTable("data");

        build.Property(a => a.Id)
             .HasColumnName("id");

        build.Property(a => a.Type)
             .HasColumnName("type")
             .HasColumnType("jsonb");

        build.Property(a => a.User)
             .HasColumnName("user")
             .HasColumnType("jsonb");
	}
}
  • 對應到 DB 的 Data Type
    • 2 個 jsonb 的 Column 都為 string
public class Data
{
	public int Id { get; set; }

	public string Type { get; set; }

	public string User { get; set; }
}
  • 執行結果,把 DB 的資料變成 string 輸出了

  • 不過拿到字串的話,在程式還需要在轉換一次才方便使用,所以我們可以使用前面文章有提過的 Value Converter 來 mapping 成強型別

使用強型別對應

  • 修改 OnModelCreating 的 mapping
    • 增加 2 個 Column 的 Converter,使用 Json.NET 進行轉換
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Data>(build =>
    {
        build.ToTable(nameof(Data).ToLower());

        build.Property(a => a.Id)
             .HasColumnName("id");

        build.Property(a => a.Type)
             .HasColumnName("type")
             .HasColumnType("jsonb")
             .HasConversion(b => JsonConvert.SerializeObject(b),
                            b => JsonConvert.DeserializeObject<string[]>(b));

        build.Property(a => a.User)
             .HasColumnName("user")
             .HasColumnType("jsonb")
             .HasConversion(b => JsonConvert.SerializeObject(b),
                            b => JsonConvert.DeserializeObject<User>(b));
    });
}
  • 修改 Data Type
    • 把 2 個 Column 的型別變成強型別
public class Data
{
    public int Id { get; set; }

    public string[] Type { get; set; }

    public User User { get; set; }
}

public class User
{
    public int Id { get; set; }

    public string Name { get; set; }
}
  • 執行結果
    • 可以看到已經轉成強型別了

同場加映,使用 Sql Command

  • 原生 PostgreSQL 有很多操作 Jsonb 方便的用法,這裡就用一個簡單的範例
    • 可以直接 where jsonb 裡面物件的 id
var id = "1";
var data = _dbContext.Data.FromSql($"select * from data where data.user->>'Id' = {id}").FirstOrDefault();
  • 執行結果

後記

  • 在 DB 可以存 Json 的格式真的很方便,可以使用的場景變多了,而且 PostgreSQL 又提供了很多相關的函式,讓我們可以很容昜的使用它,有機會可以在來介紹一些內建的函式