|
|
# T3 S6 J& w6 d: V% j& m9 \! w<h2 id="系列导航">系列导航</h2>' u3 k6 \ ^7 A' Z( h0 v
<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>( u# R2 j- v! V+ _, k/ I2 R
<h2 id="需求">需求</h2>
+ Y# z3 |# ^6 `5 [- @/ j8 b8 P) F<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>$ N/ f/ M% V: s/ B1 [/ b
<h2 id="思路">思路</h2>
% s5 P, x# d' {& \) r' s<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>& d0 A. T0 A5 h) _/ l% S1 V
<h2 id="实现">实现</h2>+ c% Y# d4 Z$ b1 t5 Q% x" {
<p>为了保持简单,我们先定义以下两个类型:</p>- g, }( O. O# E7 p& |1 F' d' w
<pre><code class="language-c#">// 定义新增Post的参数6 c: Z" I3 B* K
public record AddPostInput(string Title, string Author);
% u! T I) T2 ~5 N4 Q& t& t0 v/ o
// 定义新增Post的返回对象
/ n. n8 a% Q2 D0 o, K' X# \( Npublic record AddPostPayload(Post Post);
! u- a% s( K) [9 ?0 \, x1 l7 {</code></pre># b4 ?2 y- }$ \; F* t1 r8 r0 x
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>
) p# a7 A' F \! v U3 d( P<ul>
1 o& i3 H* z! C( s c<li><code>Mutation.cs</code></li>" B: j& K1 J$ l
</ul>
( W. i. f( W) }/ M3 M6 K. D9 `<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;
3 ]1 G' ~' r4 t: R+ K. f. _+ r
6 `9 T% A" _! d8 vpublic class Mutation
6 G! R& w& N% v1 R& G6 g4 @/ o{1 p$ y& W- _# c
public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)
! f$ j) R; l( _+ Q {9 X! {: {' H' Y- r+ {
return new AddPostPayload(await repository.AddAsync(new Post
+ v6 o ^# k9 n# w: | j, ^ {
% o/ ?) X5 M/ u Title = input.Title,6 N9 l5 Q& d3 G" g2 h) ]
Author = input.Author
; V4 ^2 I* H7 N. a% v# A2 F }));/ Q5 n. V5 {0 J: x5 ]6 x
}5 O8 u. F8 l- n( l t( H
}1 l: U* |" w4 O
) y! T5 a3 Z+ \, b* _$ I
</code></pre>
- F; k; e3 J$ @! K<p>最后在注入服务的地方进行配置:</p>
9 D, a( q! L: _& [- s3 y<ul>
1 U% @! [, `" U" `, V. I5 O) h% k1 r<li><code>ProgramExtensions.cs</code></li>
/ @/ M# w* m+ ]8 p; u" u6 @</ul>. n) z# i; N% J7 ^1 |: A; H. K
<pre><code class="language-c#">builder.Services
) V* Q( H; s2 R# j5 l& w( e .AddGraphQLServer()
1 {1 H5 x/ l. I$ f0 x5 E* @, [ .SetPagingOptions(new PagingOptions
6 a* Q" W8 m2 M; l$ m/ z0 f/ Y {* J' {9 U0 `/ ^+ l7 r. R
MaxPageSize = 50,
/ |. |; e" \: I2 o5 k9 h C IncludeTotalCount = true$ _$ i* }1 a+ y8 b Q, M }
})
r% q H8 \( r5 H7 X6 K$ m) K .AddFiltering()1 n; h2 Q% z: g4 _$ Y% m: K
.AddProjections()1 u+ e; J: l0 U4 b. [
.AddSorting()
! [9 `4 m) [ F1 R" l: u% G .AddQueryType<Query>()) V: ]1 c/ y2 `* `
.AddMutationType<Mutation>()
( M5 ^! Q0 W7 A( i5 \0 v! g* w .AddMutationConventions(new MutationConventionOptions
/ Q3 u* {& V8 l, A {
6 v) ?- l3 F4 J8 o/ m5 X3 b! a; W ApplyToAllMutations = true,
! W* N" l/ D9 W- w; G8 M InputArgumentName = "input",
3 R( p$ {9 _* i5 f3 V& n& y InputTypeNamePattern = "{MutationName}Input",
/ N9 Y1 ~) \7 o1 g X) Y PayloadTypeNamePattern = "{MutationName}Payload"," }7 |# e/ P1 h/ o: w/ r: t; w
PayloadErrorTypeNamePattern = "{MutationName}Error"," w2 H$ y. Y5 c7 F7 Z" Y7 n/ o
PayloadErrorsFieldName = "errors"
2 ^6 G) v, E+ f! B! g0 t })9 f" B9 K5 j- K+ N
.AddType<PostType>();
, t1 t. v; _& A! }/ I6 @</code></pre>
$ u7 u; |: l% w<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>
; a; \9 [9 H% B<h2 id="验证">验证</h2>6 ^! C5 S$ {; ]
<p>启动<code>Api</code>项目,调用接口:</p>
5 ~' r* O$ j7 |3 b. d<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p> K" S) x0 q6 n2 D. `% K `
<p>终端的日志输出如下:</p>4 Y" j, G0 w8 ]) v
<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']
' C8 `# H- K3 G. PINSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
: n) H1 R5 D* d$ X, G% E1 I8 V& s" UVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);
0 k5 s V9 z6 @# K[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'0 _3 @5 T' N4 }2 u# T- o4 W
</code></pre>* c" B2 S, \5 K+ N: O; A: Z
<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
4 m H1 {# @$ B& T* P) y5 n$ @<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>
$ w6 i8 p) s: a; ^0 n<h2 id="总结">总结</h2>
9 A; n; ]9 _6 b# I: }8 p8 Z<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>
7 S# t# h( Z8 r" V<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>
. p. K8 N# l/ [: }. V" u% N- p4 u' u, c" B5 E9 y3 y
|
|