|
|
# w& i- m" h- d<h2 id="系列导航">系列导航</h2>7 L9 | r1 I) _+ Q! n
<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>. t' g7 J; S, u4 L. x0 z; v
<h2 id="需求">需求</h2>
5 D( J/ e+ A/ Q( C0 G: t( p: O<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>
5 p5 D5 y6 D* D<h2 id="思路">思路</h2>+ u8 b6 Y9 l& K
<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>
3 @( c9 e& `) T2 T. }: l6 I6 w/ b<h2 id="实现">实现</h2>
! U+ @& n6 o( h+ f5 W' X<p>为了保持简单,我们先定义以下两个类型:</p>$ l! t, W9 F( k1 }3 M) g4 x! i6 X
<pre><code class="language-c#">// 定义新增Post的参数
0 T# t/ `! z" _% u( ppublic record AddPostInput(string Title, string Author);+ @6 b; Y1 s! W
) C' h+ e0 k8 ^8 A/ ^3 o" |
// 定义新增Post的返回对象
8 F, M) N8 u* K' qpublic record AddPostPayload(Post Post);
: b! c8 z/ a+ {7 Z" _& H, b. I1 C1 N</code></pre>4 @- `, @7 i. Y( z& J& K( C! T4 ?
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>6 d# F, W. q& e! q9 E
<ul>
5 ]! X' G% |+ v. ?0 c* R<li><code>Mutation.cs</code></li>4 ^1 f+ O0 Q8 z. m) ?
</ul>
8 q: \6 }8 G z<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;, a- J4 i) n9 z7 T
% h! V5 z) M" P( a3 X
public class Mutation
: T( I" c8 P2 }, o$ e{
5 H+ |) E q, k9 a$ G3 G public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)
t8 c( j5 n& K6 i0 B Z n {, d! u- \6 f! m; p7 g
return new AddPostPayload(await repository.AddAsync(new Post
% [6 y k3 {6 z6 w) `# V {& d5 o4 {- q* r9 w: _" m% G
Title = input.Title,
5 O& l$ @# c8 V. J" P% Z. x9 W Author = input.Author
& ~! F2 F6 \- l# G# g1 H& B- l }));9 D) i4 m: q; U" \
}! }8 \) {& J$ i. R
}& b/ U& W$ u# B9 A' ]4 P/ d" b3 U
2 E# r' G6 ]9 ]' C! z: m: m
</code></pre>' {6 ` F' S' h2 e3 d6 R
<p>最后在注入服务的地方进行配置:</p>
% X4 @& O0 q7 C2 P<ul>
1 C1 ^0 l( P7 g4 K, z0 j<li><code>ProgramExtensions.cs</code></li>9 l& m$ o7 u6 m1 Z# l r
</ul>
% V$ \4 K+ s; x: c1 Z) |<pre><code class="language-c#">builder.Services
& X7 ^1 ]3 L$ ~/ M .AddGraphQLServer()
5 u2 D- p5 _! i8 J3 o- l" J- {0 J" a4 D .SetPagingOptions(new PagingOptions
1 O( L+ E1 K0 m9 i/ p( C( q {7 p& ~! N A; L8 Z/ F& Y% G1 c
MaxPageSize = 50,& L( R' x3 ?& {* P8 q! O2 S* U
IncludeTotalCount = true
3 j/ V8 W" z. i7 K( ] })2 H- M1 L0 M- o/ n) k) k+ t
.AddFiltering()
# ^1 j" F3 { e$ E .AddProjections()
; |+ ?( H3 h9 k/ {8 x .AddSorting()
- g& b: E, Z7 \8 Q .AddQueryType<Query>()+ j8 Z& @5 U3 u% _) G( w7 P* F! _
.AddMutationType<Mutation>()
6 V# F% g3 Y9 Q6 a P X .AddMutationConventions(new MutationConventionOptions2 i, j5 V( b: s2 f( g
{1 m" d! q; M- p) ^# U
ApplyToAllMutations = true,6 I) q3 P& S, T7 Y( G* B& C
InputArgumentName = "input",# S( G; ^- B& r
InputTypeNamePattern = "{MutationName}Input",
5 f( d9 k+ [# w; L+ T% l. W PayloadTypeNamePattern = "{MutationName}Payload",/ u& F6 ]! F7 F
PayloadErrorTypeNamePattern = "{MutationName}Error",
( D1 {: i4 R" E! `! P4 c7 a9 |& b PayloadErrorsFieldName = "errors" U9 Y- n& w- \: C7 z
})/ q8 l; c; S) ]2 ~! e5 R2 B
.AddType<PostType>();: L/ c! t' {3 M9 t5 s6 O
</code></pre>
6 M$ t% [8 {: {0 N9 ^; e- C% a2 O. ^! ]) E<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>
6 w. f6 D' e$ y+ Z<h2 id="验证">验证</h2>: K! V5 _4 L2 I/ a$ a
<p>启动<code>Api</code>项目,调用接口:</p>& V$ y, s) U* Y8 S
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>2 |3 C, E2 E) z2 \: N& p
<p>终端的日志输出如下:</p>4 O* y, L) d2 p5 d/ k
<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']
7 k' n- d! u' y2 }3 p2 P% ~INSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
: B. \! P* F4 W3 q; e. cVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);2 T6 U' ?. N" ]5 Y2 x" _
[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'. X! I1 r! {6 L' T$ m: ^
</code></pre># z- z; @- |/ c6 n2 I2 L: [. S' V
<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
9 T9 O% e5 } `# n6 j& B# P<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>
7 }2 o: ?" t' ]. b<h2 id="总结">总结</h2>+ s+ T* T) ~" |% W: U; A
<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>5 V& e) W0 Y9 G1 D; ~* N
<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>0 U( S/ o" ~' I4 e6 j+ V4 @ T6 M; T
4 U) e$ R0 a& w! l
|
|