|
|
; L) l" J5 B. c; c( r) W) G- f1 A
<h2 id="系列导航">系列导航</h2>: ~% b$ _# X4 A% {5 d0 N( q0 N
<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>
7 ?. e+ `0 |+ T- A, C3 T3 z3 h<h2 id="需求">需求</h2>2 }3 c0 `' t5 R \ L7 p
<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p># I0 X* z9 x9 S2 F- ]7 [" `4 }/ v- ^
<h2 id="思路">思路</h2>
+ t5 K3 m6 [1 I! W$ ^! G" o<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>$ f0 }: ~) O, [8 g/ D
<h2 id="实现">实现</h2>
( g+ Y# K' O% U/ k$ E<p>为了保持简单,我们先定义以下两个类型:</p>
" u" }! g" ^7 m+ @& z, C1 H# J<pre><code class="language-c#">// 定义新增Post的参数
5 P9 t1 v2 H! x' m- p# v4 W( Mpublic record AddPostInput(string Title, string Author);
6 g2 i4 M+ O5 A- @& e9 T$ j- O
3 h8 S1 g7 l1 X9 i# X/ _: z// 定义新增Post的返回对象; a3 g! Y( B) f# l7 V
public record AddPostPayload(Post Post);
' `3 s, J" C4 t$ Y. K8 U+ O: ~% D* N" _</code></pre>, a" k' y7 v, I( ~" W' `. c
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>
" f% n* }; F. L0 P. J1 y9 _<ul>
, m; b$ J% G0 u$ |<li><code>Mutation.cs</code></li>
+ \+ q: {; O# k/ V" d/ f</ul>, c8 D% U; l |; T; R+ ~6 ~
<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;& K' `6 z! X# D% P: a5 m
l8 |# [8 V9 N, M5 Z! Wpublic class Mutation2 B) d" U2 K3 @7 n8 A" A B0 J
{
8 B i$ R8 t) l public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)+ j+ J3 ?" O& ~) d: k* ~
{
/ ` J4 x1 G/ b! S return new AddPostPayload(await repository.AddAsync(new Post; e; v( M6 Y9 U9 j/ v( s4 G! c
{
& g- G7 {, W6 x& Y( L+ @9 z' }/ k Title = input.Title,, O2 m9 S* _. [$ G& ^8 V9 E# t
Author = input.Author
; d0 n2 M i+ q, H3 u# v }));! n0 z! y& V+ v
}
$ W1 \- P9 Y9 R0 t7 t$ s+ |}
* K0 R* l0 p u5 q1 v' v% Z3 U) _0 v* F8 F7 g
</code></pre>% @* y2 f" ]" A! p& O/ Y( Z, v8 K
<p>最后在注入服务的地方进行配置:</p>8 P# h. U; O* H: U& Q" W
<ul>
3 Q. D/ Q6 W- @+ V* Y9 T5 e& V<li><code>ProgramExtensions.cs</code></li>) ~) ]$ Q4 i9 d9 P8 {* D
</ul>
3 z6 I+ e' A; Y" h2 s5 _<pre><code class="language-c#">builder.Services
V" k) _$ ^" ^* K .AddGraphQLServer()3 O m. T4 A! X, D& o( k, p
.SetPagingOptions(new PagingOptions% |5 C* s# ^6 e- U0 \
{4 Q7 }7 E8 a6 ~ X( |! v. c, s# D
MaxPageSize = 50,
( G; F* c4 k, W/ ^6 b- V# @5 J* Z IncludeTotalCount = true$ l ]" z( f( F- h9 Z5 s" f# a
})
" u! d5 Z3 J* k9 i; ~6 X1 b .AddFiltering()
& z, I+ ]7 |, e1 m& p! x: U .AddProjections()
9 F" I* G; s) u; C& X .AddSorting()
: m& A) X' E1 i) f4 I' X .AddQueryType<Query>()5 T1 [. g' g/ h! \/ |5 M% i8 U
.AddMutationType<Mutation>()
" D5 O: x% v7 v5 X .AddMutationConventions(new MutationConventionOptions8 F4 a& {( j/ J+ q5 c1 `; G
{7 v/ _- @4 A6 l+ x* t
ApplyToAllMutations = true,
+ ~+ J+ @' o2 M6 X" _, W9 V InputArgumentName = "input",' U; O0 r m+ L" h+ m) H8 O
InputTypeNamePattern = "{MutationName}Input",
/ {$ d7 `" ~9 N* W PayloadTypeNamePattern = "{MutationName}Payload",9 U3 Q H/ W4 l$ X1 d
PayloadErrorTypeNamePattern = "{MutationName}Error",+ t$ C0 W, J& K0 j; t
PayloadErrorsFieldName = "errors"7 F- W" ]8 @! u/ s& r; F
})
! g) ?" H4 u) I# k8 M& H .AddType<PostType>();( o' {4 a; |" b; I9 G4 ~6 l5 o
</code></pre>
5 b$ l' U) t8 l<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>. z4 G, O! C2 c1 k5 m
<h2 id="验证">验证</h2> I' ?( g& T9 a5 D5 v
<p>启动<code>Api</code>项目,调用接口:</p>' r2 d8 |$ Q0 M0 o
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>6 f I5 d' ~6 m
<p>终端的日志输出如下:</p>5 @, _6 O' i1 a' b# R
<pre><code class="language-bash">[10:45:15 INF] Executed DbCommand (1ms) [Parameters=[@p0='?' (DbType = Guid), @p1='?', @p2='?' (Size = 13), @p3='?', @p4='?' (DbType = DateTime), @p5='?', @p6='?' (DbType = DateTime), @p7='?', @p8='?', @p9='?' (DbType = DateTime), @p10='?' (Size = 30)], CommandType='Text', CommandTimeout='30']$ j4 j- i* L9 V: _: }. j5 ?
INSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")- e6 X; s9 O u
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);/ L: S$ a/ y; {! X! Y4 B! Z* Y
[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'
& e. N, K0 Y K9 I8 l4 D</code></pre># w# D( f4 V- @" r' K$ X
<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>' j8 b8 Y, m* X. `! h7 u/ |! A5 u7 K
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>
5 H# o6 r* l: {- X" C; ~. ~% T9 i<h2 id="总结">总结</h2>
k* b( w# }6 J1 _; D; T<p>在本文中我们实现了简单的新增Post操作,这里还有一些涉及到错误处理的内容,我没有在文章中演示,可以参考官方文档 <a href="https://chillicream.com/docs/hotchocolate/defining-a-schema/mutations/#errors">Errors</a>,在自定义异常对象后,有三种方式可以进行错误处理:直接返回异常;使用异常工厂方法;使用构造函数。甚至可以在<code>AggregateExceptions</code>中一次性返回多个异常。基本思路都是通过添加属性<code>[Error(typeof(SomeUserDefinedException))]</code>来实现的。</p>: }+ @; c) u/ X: U* k- m
<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>
2 V4 D5 `9 W2 R( K) t- n3 }9 R# ?# a+ L+ `8 ]5 G
|
|