|
|
( J. V7 y$ d/ ~) ?
<h2 id="系列导航">系列导航</h2>8 n7 j* K: M/ u
<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>
- f& u3 a; K9 ^2 I) j+ J& ]. h<h2 id="需求">需求</h2>
# c$ c7 |( _. M7 H+ W<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>
2 o; e7 f3 v7 F9 c8 S3 L<h2 id="思路">思路</h2>7 ], k4 ~$ K# K; m/ f$ i- J1 }/ R
<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>2 J% i" e; n8 n2 |" Q" a5 X0 ~
<h2 id="实现">实现</h2>
+ \3 h6 c- C! R$ N<p>为了保持简单,我们先定义以下两个类型:</p>' l9 V; E, i1 e( G# o
<pre><code class="language-c#">// 定义新增Post的参数# p- `# x) Y+ ~( s+ A0 W6 N/ [
public record AddPostInput(string Title, string Author);
- f8 ~: L' p$ H$ y1 L- T
- m$ ^ G. D; i% G2 ?- }( i; I// 定义新增Post的返回对象. A% U) H* [$ i2 p
public record AddPostPayload(Post Post);
! g M" W% J- C6 y2 D</code></pre>* B: k+ M$ g. w3 P4 z' O3 v
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>* R& R) ~# v0 Y( c7 R3 \/ r5 U0 C& v
<ul>
. w9 b1 s6 Y% D* q6 k6 q$ }<li><code>Mutation.cs</code></li>
8 j7 s Z- A$ R8 A; a# J4 S+ b, N</ul>
6 n- U6 z" `$ x/ l: T5 }<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;+ M4 |7 I( f) D+ m; k; C9 T n
) W. M W$ K! U/ |* H" i8 y1 B Z
public class Mutation! D0 ^( u) B- p7 s
{' j* H2 P/ @+ L2 \$ l2 k
public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)9 l9 n a! N& o9 g1 U" C
{
' ?. I; w8 } C9 @ return new AddPostPayload(await repository.AddAsync(new Post# h3 B: z+ `2 T
{# G- }/ D/ h6 `. m0 ^
Title = input.Title,4 t! s8 s F8 V: L7 Z2 ?" K% m
Author = input.Author
4 z: |: a x- e S }));/ i/ g7 Z& [$ Q$ f
}
6 l8 C2 n5 i$ G3 _( P& d}
* K( d }, n- s& Q( | l+ y# Z6 Y! h: f$ w$ l
</code></pre>; |/ k! g" h2 D0 w" o
<p>最后在注入服务的地方进行配置:</p>! X/ ?9 Z: S% P5 R
<ul>8 |/ {* U/ e" Z# z$ }
<li><code>ProgramExtensions.cs</code></li>$ w$ b) F, u+ o' i
</ul>
/ D! t6 ^: f/ J' ~4 ]: n9 j J<pre><code class="language-c#">builder.Services
) c: J9 i. D5 U. h4 J* ]( M2 A .AddGraphQLServer()
5 f3 o5 E; t$ L6 y8 o8 G .SetPagingOptions(new PagingOptions
+ e/ t0 y ?2 f+ k0 r4 E {( }" e# C; Z: H7 g1 O- c7 V, }: b' {" X
MaxPageSize = 50,. m% r* ^* z, \
IncludeTotalCount = true
$ E3 I [; q9 S+ S }); k, ?' h7 [8 M8 f0 U& I
.AddFiltering()
, j1 c( u6 K: e& S' g* W .AddProjections()8 i3 Q( e. b8 Y |" d
.AddSorting()
$ M1 x. L! G% S$ \7 J* y8 E7 P .AddQueryType<Query>()3 A0 j7 P1 p+ c7 e
.AddMutationType<Mutation>()4 Q. N3 O" f( b9 T2 ^ _+ n
.AddMutationConventions(new MutationConventionOptions4 x& |- L2 ]- w( \
{3 v4 g* |$ V9 p* e1 [, l1 I7 C
ApplyToAllMutations = true,
+ M2 ^0 }2 _4 {4 z InputArgumentName = "input",, e F8 k7 ?; r$ J
InputTypeNamePattern = "{MutationName}Input",- a4 k) ]1 C1 g9 s9 W$ R. {7 |* n; W
PayloadTypeNamePattern = "{MutationName}Payload",
( m# f0 |. x) H0 Q$ D PayloadErrorTypeNamePattern = "{MutationName}Error",1 c8 M7 q+ ]1 P. T4 b+ l0 w
PayloadErrorsFieldName = "errors"
+ `! Z- y+ C/ t+ e4 E8 ^4 d }); F! l& L& i; c
.AddType<PostType>();0 P) T- S2 E1 G p4 V
</code></pre>( e# ^ e, T! U$ ?9 N5 a, P4 U( ~% U& v
<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>
+ Y0 c; l: ~* e9 p a<h2 id="验证">验证</h2>
+ @4 F* r% @! J% c# U+ y) K2 n<p>启动<code>Api</code>项目,调用接口:</p>, i8 }9 p) F! m
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>' r, \0 r, o7 S: A( {" y: G
<p>终端的日志输出如下:</p>1 j9 Q) l: F2 A }' q
<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']
* p& L F8 l& d- Y4 X0 C4 UINSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
) C8 n( Y1 P' }1 d/ j# IVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);
/ D: }+ s$ @) C" S, m0 }- N[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'! [# c% h: H9 y* w( \3 n
</code></pre>
, Y) P7 X9 \) x<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
5 V5 ^- D! n! u& X1 W% b<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>
1 I9 z A: S4 X" A0 Q, a; C<h2 id="总结">总结</h2>3 t6 f. J- \ p$ C! C
<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 j* X) r8 d. ?( W# ]: \! V! q Z2 B<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>
) P' y' u& r/ J% v) _1 J# ~& a! {2 X/ u1 }% h
|
|