使用Hot Chocolate和.NET 6構建GraphQL應用(9) —— 實現Mutate更新數據
系列導航
使用Hot Chocolate和.NET 6構建GraphQL應用文章索引
需求
在上一篇文章中,我們演示了如何使用Hot Chocolate進行GraphQL的Mutate新增數據,這篇文章我們將演示如何實現GraphQL中的數據更新任務。
思路
對數據的更新和新增數據的思路是一樣的,都是使用Mutate機制進行更新。
實現
為了保持簡單,我們先定義以下兩個類型:
// 定義更新Post的參數
public record UpdatePostInput(Guid Id, string Title, string Author);
// 定義新增Post的返回對象
public record UpdatePostPayload(Post Post);
新建Mutation.cs用來定義相關介面:
Mutation.cs
public async Task<UpdatePostPayload> UpdatePostAsync(UpdatePostInput input, [Service] IRepository<Post> repository)
{
var post = await repository.GetSingleAsync(p => p.Id == input.Id);
if (post == null)
{
throw new ArgumentException($"no post with id: {input.Id} can be found!");
}
post.Title = input.Title;
post.Author = input.Author;
return new UpdatePostPayload(await repository.UpdateAsync(post));
}
這樣就實現了更新Post的需求,下面我們來驗證一下。
驗證
啟動Api項目,先查詢所有的Post數據:

接下來對其中一條Post進行更新:

終端的日誌輸出如下:
[15:44:17 INF] Executing endpoint 'Hot Chocolate GraphQL Pipeline'
[15:44:17 INF] Executed DbCommand (0ms) [Parameters=[@__input_Id_0='?' (DbType = Guid)], CommandType='Text', CommandTimeout='30']
SELECT "p"."Id", "p"."Abstraction", "p"."Author", "p"."Content", "p"."Created", "p"."CreatedBy", "p"."LastModified", "p"."LastModifiedBy", "p"."Link", "p"."PublishedAt", "p"."Title"
FROM "Posts" AS "p"
WHERE "p"."Id" = @__input_Id_0
LIMIT 1
[15:44:17 INF] Executed DbCommand (0ms) [Parameters=[@p10='?' (DbType = Guid), @p0='?' (Size = 66), @p1='?' (Size = 22), @p2='?' (Size = 30), @p3='?' (DbType = DateTime), @p4='?', @p5='?' (DbType = DateTime), @p6='?', @p7='?' (Size = 26), @p8='?' (DbType = DateTime), @p9='?' (Size = 59)], CommandType='Text', CommandTimeout='30']
UPDATE "Posts" SET "Abstraction" = @p0, "Author" = @p1, "Content" = @p2, "Created" = @p3, "CreatedBy" = @p4, "LastModified" = @p5, "LastModifiedBy" = @p6, "Link" = @p7, "PublishedAt" = @p8, "Title" = @p9
WHERE "Id" = @p10;
SELECT changes();
[15:44:17 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'
[15:44:17 INF] Request finished HTTP/1.1 POST //localhost:7194/graphql application/json 288 - 200 - application/json;+charset=utf-8 8.6091ms
再進行一次查詢:

可以看到更新後的Post已經存儲到資料庫中了。
如果我們使用錯誤的Id去嘗試更新數據,那麼會得到這樣的返回:

但是這樣我們並不能看到具體的錯誤資訊,即使我們在程式碼中已經明確throw了異常並填入了錯誤資訊。接下來我們來解決這個問題。
擴展:自定義異常返回
為了讓GraphQL的schema能夠識別異常類型,最簡單的方式是通過屬性[Error(typeof())]來指定異常類型,我們當然可以穿入ArgumentException異常類型,為了演示如何自定義異常類型。我們新建一個異常類:
namespace PostGraphi.Api.GraphQL.Exceptions;
public class PostNotFoundException : Exception
{
public PostNotFoundException(Guid id)
: base($"no post with id: {id} can be found!")
{
}
}
並修改Mutate方法屬性和拋出異常的程式碼:
[Error(typeof(PostNotFoundException))]
public async Task<UpdatePostPayload> UpdatePostAsync(UpdatePostInput input, [Service] IRepository<Post> repository)
{
var post = await repository.GetSingleAsync(p => p.Id == input.Id);
if (post == null)
{
throw new PostNotFoundException(input.Id);
}
post.Title = input.Title;
post.Author = input.Author;
return new UpdatePostPayload(await repository.UpdateAsync(post));
}
最後還需要在引入依賴的時候進行配置,選擇返回結果中包含具體的錯誤資訊:
builder.Services
.AddGraphQLServer()
// .....
.ModifyRequestOptions(opt => opt.IncludeExceptionDetails = true);
再來測試一下:

在extension中我們看到了自定義的錯誤資訊輸出。
總結
在本文中我們實現了簡單的更新Post操作,對於刪除數據來說,思路並沒有區別,所以我們下一篇文章將會直接介紹GraphQL中的另一大特性:Subscription。

