0%

postgresql ef core 使用 json 欄位

 

佛心幫朋友爬資料遇到的問題, 朋友想爬老外的資料, 研究下是前後分離架構, 從 OAuthapi, 預設會用 OData 丟個肥大的巢狀 json 回來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"id": "1xz3x938-x386-41x2-x922-aaxxxb21caee",
"date": "2021-01-12T01:16:37Z",
"temperature": 53.5,
"powerStatus": {
"id": "Ok",
"displayName": "Ok"
},
"power" : 1.23,
"battery": 4.39,
"company": {
"id": "3212x5c0-6700-o779-o6a5-dx16626x7fzz",
"name": "QQ"
},
"readingValues": {
"AC": {
"value": 0,
"description": "ooxx",
"realValue": "Volts",
"valueClass": "Reading",
"rmuSlot": 5,
"display": 2
},
"DC" : {

}
}
}

可以到這些網站讓他轉為類別
https://transform.tools/json-to-typescript
https://quicktype.io/typescript
https://www.codeconvert.ai/typescript-to-csharp-converter

特別注意類別屬性要用 JsonPropertyName 去指定, 不然會得到 null, 如果用 Newtonsoft 則是 JsonProperty

1
2
3
4
5
6
7
8
public class AcLineStatus
{
[JsonPropertyName("id")]
public string Id { get; set; }

[JsonPropertyName("displayName")]
public string DisplayName { get; set; }
}

分析完後建立資料表, 這裡命名時要注意下, 因為 ef core 會用 .net 風格的命名
如果想用 postgresql 風格的話, 可以考慮安裝 EFCore.NamingConventions

1
2
3
4
5
create database crawler;
create table station (
id uuid primary key,
data_row json
);

可以在 Program 設定 NamingConvention, 另外想看到丟什麼參數進去要把 EnableSensitiveDataLogging 打開

1
2
3
4
5
6
7
8
builder.Services.AddDbContext<CrawlerDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("PG"));
options.UseSnakeCaseNamingConvention();
//options.UseLowerCaseNamingConvention();
options.EnableDetailedErrors();
options.EnableSensitiveDataLogging();
});

研究下發現 ef core 7ToJson 這個新功能
可是這個情境因為 json 太過巢狀用起來卡手卡腳, 最後放棄還是改回 string 的用法, 如果 json 不複雜的話倒是可以玩看看
不過他有個問題就是沒法指定資料庫的 ColumnName 例如這裡寫 JsonDataRow, 資料庫欄位也要一致, 也可能我沒找到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

modelBuilder.Entity<Station>(x =>
{
x.OwnsOne(x => x.JsonDataRow, builder =>
{
builder.ToJson();
});
});

OnModelCreatingPartial(modelBuilder);
}

public class Station {
public Guid Id {get;set;}
pbulic JsonDataRow JsonDataRow {get;set;}
}

如果要用 string 則這樣寫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class JsonDataRow {
public Guid Id {get;set;}
pbulic string JsonDataRow {get;set;}
}

[ApiController]
[Route("[controller]")]
public class StationController : ControllerBase
{
private CrawlerDbContext db;
public StationController(CrawlerDbContext db)
{
this.db = db;
}

[HttpGet]
public IActionResult Get()
{
var result = db.Station.ToList();
var list = new List<Station>();
foreach (var item in result)
{
var json = JsonSerializer.Deserialize<JsonDataRow>(item.JsonDataRow);
list.Add(json);
}
return Ok(list);
}

}
關閉