0%

asp.net core odata 筆記

 

被朋友凹的咚咚, 因為平常已經累得很狗沒兩樣, 也沒那美國時間寫一堆客製化的 api, 想說偷懶插個 OData 模組來減輕開發負擔
不過因為資料結構是存 json 所以沒辦法發揮 OData 更強的威力, 資料筆數少的話才可以這樣搞, 就是前端免額外處理一堆複雜的 filter 或排序, 直接用 OData 下即可
玩一玩覺得 OData 這東西不錯啊, 不曉得為何沒多少人在用, 甚至聽都沒聽過 @. @

安裝及設定

安裝的部分要注意的應該就是 json 要丟 .net 8 預設的還是要用 NewtonsoftJson
另外我是用 postgresql, 所以搞 ef core 資料表可能會需要用 EFCore.NamingConventions 才能符合 coding style

1
2
3
dotnet add package Microsoft.AspNetCore.OData
dotnet add package Microsoft.AspNetCore.OData.NewtonsoftJson
dotnet add package EFCore.NamingConventions

實作可以參考官網, 如果沒有巢狀 json 的話應該就還好, 巢狀還要下 expand, 感覺滿複雜 QQ

因為我是偷懶在 postgresql 直接用 json 存爬回來的資料, 所以 model 相對單純

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Table("qq")]
public class QQ
{
[Column("id")]
public Guid Id { get; set; }

[Column("datarow")]
public string DataRow { get; set; }

}

public class DataRow
{
[JsonPropertyName("id")]
public Guid Id { get; set; }

[JsonPropertyName("readingDate")]
public string ReadingDate { get; set; }

[JsonPropertyName("temperature")]
public double? Temperature { get; set; }
}

Program 設定也滿簡單, 看要開哪些 OData 操作的功能就加上去, 在這前端哀東哀西的年代, 串起來就是省事, 快樂收工 XD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<DataRow>("DataRows");
modelBuilder.EnableLowerCamelCase();

builder.Services.AddDbContext<CrawlerDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("QQ"));
options.UseSnakeCaseNamingConvention();
options.EnableDetailedErrors();
options.EnableSensitiveDataLogging();
});

builder.Services.AddControllers()
.AddOData(options =>
{
options.Select()
.Filter()
.OrderBy()
.Expand()
.Count()
.SetMaxTop(null)
.AddRouteComponents("odata", modelBuilder.GetEdmModel());
});

controller 名稱地雷

因為我本來有一個 QQController 另外一個想用 QQODataController 這裡會雷到
需要自己在 QQODataController 上面去加上 [Route(“odata”)] 手動指定
另外這裡我有嘗試用 IQueryableSelect Deserialize 的結果, 不過 ef core 會噴錯, 如果有效能考量就不建議這樣寫, 單純只是偷懶用 ~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Route("odata")]
public class QQODataController : ODataController
{
private CrawlerDbContext db;
public QQODataController(CrawlerDbContext db)
{
this.db = db;
}

[EnableQuery]
[HttpGet("DataRows")]
public ActionResult<List<DataRow>> Get()
{
var result = db.QQ.ToList();
var list = new List<DataRow>();
foreach (var item in result)
{
var json = JsonSerializer.Deserialize<DataRow>(item.DataRow);
list.Add(json);
}
return Ok(list);
}
}

吐出 Json 大寫的問題

這個還滿地雷的, 就算用 .net 8 預設是大寫開頭, 看老外丟出來都是小寫開頭的風格, 查了一陣子發現要這樣設定

1
2
3
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<DataRow>("DataRows");
modelBuilder.EnableLowerCamelCase();

看有個老外這樣寫, 不過我試起來沒辦法, 就忘了它吧 XD

1
2
3
4
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
})

Debug 問題

因為對 OData 相對陌生, 查了下發現有這個選項 UseODataRouteDebug, 他會把路徑給列出來

1
2
3
var app = builder.Build();

app.UseODataRouteDebug();

OData 語法範例

詳情可以看官網文件

只撈 Id Temperature

1
http://localhost:5000/odata/DataRows?select=Id,Temperature

羅列出欄位為 Id BatteryReading Temperature
並且篩選 Temperature 溫度大於 53
最後以 Temperature 排序

1
http://localhost:5000/odata/DataRows?select=Id,BatteryReading,Temperature&filter=Temperature%20gt%2053&orderBy=Temperature
關閉