|
! E* U4 P0 Z+ G7 `/ K<h2 id="系列导航">系列导航</h2>( Z* b* r n- m! \& b2 N/ t- \5 z
<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>
R/ A- H2 I6 g- i, ?) H<h2 id="需求">需求</h2>' V% q+ a# o9 u7 o" b
<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>) M! l, N/ Z2 c
<h2 id="思路">思路</h2>4 i( R* Z$ G/ k( M! [1 V& f
<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>
6 n2 I" Y+ B/ j<h2 id="实现">实现</h2>& }* x8 R' Q) k2 @5 a
<p>为了保持简单,我们先定义以下两个类型:</p>
% ]4 B6 j8 F# n; b0 ~* \<pre><code class="language-c#">// 定义新增Post的参数
) R# r+ Q- D0 @' O0 gpublic record AddPostInput(string Title, string Author);: Q2 M% w1 i9 `- Q' P
) V9 D/ ?! \4 P; }- R' U- h// 定义新增Post的返回对象7 ^5 r+ s/ R% n0 s
public record AddPostPayload(Post Post);- p# N6 E' I3 t1 {6 M2 I+ y% V
</code></pre>) q, `6 k4 F: \4 _- \5 O
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>: J3 w$ d/ }) J; Z! k0 F
<ul>) f5 W! T- v! Z, A6 q/ R7 C
<li><code>Mutation.cs</code></li>
% P' }9 r5 z0 @+ P7 L</ul>
, k# f8 g, l! ]3 H( l<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;( q0 B* y5 p7 Z b7 ^
E! @! r/ ~3 ^; Dpublic class Mutation! z) G8 R/ Z' L. t
{
/ n- R( v Q; D) v4 N1 X/ J; ] public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)! P! n2 ~7 e- I: I% V, T
{4 D( u3 z7 ]" C- H9 t& F% F
return new AddPostPayload(await repository.AddAsync(new Post; t$ x3 | J4 ]) }0 \8 c! f
{
7 g+ l- b( \* d+ e, p Title = input.Title,
: R; b8 |+ q' h* L* C+ a Author = input.Author. P' [8 v, h4 c9 ?: @9 N; D5 a! a3 A
}));
$ G } `0 a; G0 g B }6 J+ R% o! U3 ~) F
}1 W9 M2 ?6 [% Q/ U5 m
. j2 A9 Z3 p) I& M2 N# {</code></pre>. k: F1 v* k. |
<p>最后在注入服务的地方进行配置:</p>
/ g3 k( e) C* l, {2 D2 T: D& H6 l2 ^<ul>2 G3 \7 z8 x4 n
<li><code>ProgramExtensions.cs</code></li>) i6 X' u o; j5 W
</ul>5 L1 S. s1 K/ D; N" a5 b
<pre><code class="language-c#">builder.Services4 Q5 f9 A. \( a5 V
.AddGraphQLServer()
& W7 U- i! V! ^ q/ S/ \ .SetPagingOptions(new PagingOptions$ t7 z+ F/ y$ ~$ Z
{
+ ]1 T4 e- p4 n! I! k' t5 a MaxPageSize = 50, C+ P7 f8 J3 F; |( u0 ~$ ^! N$ C
IncludeTotalCount = true
& G- L, ?* @# Z! H5 O })
. d( Y* w/ v$ }6 g2 U( X5 _) B .AddFiltering(): A3 P+ Z) {5 s z' k6 H G
.AddProjections()
' l- {. I8 K1 T9 p5 X. y .AddSorting()
8 g/ r/ m) _$ ^$ W# }: m .AddQueryType<Query>()
- G- d! ?6 O @4 Q1 `- q. t .AddMutationType<Mutation>()4 P+ S6 s% }8 E# J
.AddMutationConventions(new MutationConventionOptions
8 H/ y! n+ F" f" j {
; X" @5 R& L* y, c% B: v ApplyToAllMutations = true,
- g) x6 e5 o6 B# _4 ]: a. } InputArgumentName = "input",
# |% V' i8 V, C- }: q+ r; Y, r InputTypeNamePattern = "{MutationName}Input",+ K |' A# ^8 Y r; p6 s% r
PayloadTypeNamePattern = "{MutationName}Payload",
D5 N( I5 G! f! Q5 F( P+ {& [ d PayloadErrorTypeNamePattern = "{MutationName}Error",
' u- Y/ X/ n& g5 H& P" ` PayloadErrorsFieldName = "errors"
% s% D; R; h0 x3 ]/ C: q })
$ l. q4 J. K; `& {1 z4 Z ^& x .AddType<PostType>(); H$ i* R! O7 a$ j7 M
</code></pre>/ e: {3 o7 J9 r3 M, q( o y+ k2 V
<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>7 ?8 w6 d4 L6 k( ?: h
<h2 id="验证">验证</h2>
* i4 }! T! }; O<p>启动<code>Api</code>项目,调用接口:</p>9 C7 P: G" p& x" N+ D+ }, L
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>
6 j, d: h; t# `# F1 S<p>终端的日志输出如下:</p>
; Q. Q6 V' H8 z! f7 o: S<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']
3 i. r6 e( t+ R$ M) x8 y5 EINSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
" T! |, x9 P) BVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);
6 r9 C& B1 w5 }5 C[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'
; Y, x3 x d) |8 |. j</code></pre>0 L L* Z) I& G; K8 x
<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
0 m( J- C. ^( D; G! x<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>
* f) ^: Y/ g5 J7 b2 u, ~) q<h2 id="总结">总结</h2>
0 u. G4 r7 n& L<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>
! E- u0 i. v" R9 |! d<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>
" \2 F( Z8 x( Z/ E
- T9 P! G9 l i2 T |
|