|
|
, ~3 Q0 E1 Q. ?4 Y* K g1 H
<h2 id="系列导航">系列导航</h2>
% j; x" y! T& i: i+ t) K/ E<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>
8 |% y9 i- I7 g, D<h2 id="需求">需求</h2>
g: u" _9 G5 m) R# H<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>
8 _% `$ l* d$ k<h2 id="思路">思路</h2>" J0 B+ {0 w, ]1 T
<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>
5 L$ |4 k: n @) a+ Q1 j" A( r<h2 id="实现">实现</h2>3 m2 f2 o& T5 b. a) S4 {
<p>为了保持简单,我们先定义以下两个类型:</p>0 m# u- I7 c* t* ^8 ~% l4 u' B
<pre><code class="language-c#">// 定义新增Post的参数2 t- K" `- i/ n
public record AddPostInput(string Title, string Author);2 n3 q$ E; ^1 f8 ?2 |# A/ j3 I
+ `4 N a$ A0 x! Y. r! K/ a+ w
// 定义新增Post的返回对象- q( S! W9 ]+ e
public record AddPostPayload(Post Post);
- f0 e* r* O( B& n</code></pre>; R) K3 W( P; J' m9 C- h* g
<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>' w+ F* j8 o4 [; m
<ul>, g- z8 e- ~5 b8 E9 E3 j
<li><code>Mutation.cs</code></li>7 ]8 ^& Q( U' B0 o/ ^- g! W
</ul>
: D6 Z" e- M9 @) z<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;
& r# a" A* C$ L+ y9 _% C* w6 N" j. q/ e
public class Mutation
. V6 N9 M/ x" M( j6 Y{# D9 N& E- {4 A3 i
public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)
; d- z4 N. j- _: r {
$ r4 c0 N3 F) z6 y6 a return new AddPostPayload(await repository.AddAsync(new Post3 y: `2 d. [ W
{/ X p- D% V: O
Title = input.Title,0 A9 N" r1 Z# O* j
Author = input.Author
6 R+ C1 L, T& y7 d+ a }));
- S! m9 u( h$ K8 M+ R8 i: U! |9 ] }
. u* @% C* A6 a5 J) D. ~; t}& e4 V4 b, ]5 T# u/ @
% N9 ~, R3 b) w w* X4 R* i
</code></pre>5 h6 F d9 A8 {7 x4 y
<p>最后在注入服务的地方进行配置:</p>
) q. d1 B, j& U* M6 h- g( @' x<ul>( Y) |) k% ?) a! [5 k
<li><code>ProgramExtensions.cs</code></li>, s% {# k+ |' o3 Y
</ul>
$ x4 @* r1 q. K( {1 y<pre><code class="language-c#">builder.Services
" y) Q$ W5 N u- [. m: X .AddGraphQLServer()
& m8 R: [( H' f/ J* L) v, G, i .SetPagingOptions(new PagingOptions
- X E+ }% o- a3 J, T {
7 ~; u4 T% c e6 `4 D MaxPageSize = 50,
, ~, s- p5 J( a7 K& ~3 f& m' D IncludeTotalCount = true
0 j) E7 n; n' M3 T })
' m, r+ N$ L# B, }: Z9 e& |' ` .AddFiltering()' [- ^ W$ U+ g, L+ T: V4 @, m; a
.AddProjections()
+ N$ U* n. x+ _& j7 I% S9 K .AddSorting()
. \+ _4 Q6 v" h9 i# D' ]( Y* ?8 R .AddQueryType<Query>()' r8 c$ i* ~/ Y7 N
.AddMutationType<Mutation>()
( |( q* U. S! @- u) y .AddMutationConventions(new MutationConventionOptions
7 H* |8 D. G5 I, L3 _+ t { X- h% h, X) l6 T) Z; K* u
ApplyToAllMutations = true,- v" y- c2 t- Z- N5 H+ U
InputArgumentName = "input",) C6 W6 ~6 u# G* o7 L
InputTypeNamePattern = "{MutationName}Input",' K0 r: d( N3 M. K, C! Z
PayloadTypeNamePattern = "{MutationName}Payload",& {) \- a5 J1 H: h( u+ w! E3 h3 y
PayloadErrorTypeNamePattern = "{MutationName}Error", a5 X- p. f( z: R
PayloadErrorsFieldName = "errors"
6 e o1 X/ w# t2 ~ })
& N) c' M- d2 h3 V! c2 R .AddType<PostType>();4 T9 L/ p! E; n6 q) {( A& ~
</code></pre>- Q$ v+ b% a6 Y% H/ T& l* @
<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>& P B* Q. T+ {" A+ H: W7 e
<h2 id="验证">验证</h2>
6 ]* J+ G2 \) S<p>启动<code>Api</code>项目,调用接口:</p>- c* j* `$ M" y) e0 C
<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>. r( r, e7 i, L/ M
<p>终端的日志输出如下:</p>
`+ P( n0 K z7 o/ N1 I5 ^2 W<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']+ Z: v) |. X! m; }
INSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
" w% |0 |8 w, w+ z$ N9 GVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);, t4 I- y j" ^2 U
[10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'% {2 h" f7 G8 r' u2 L
</code></pre>" l) Q, p A; I @
<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
* Y' \5 N* h T' |2 Y5 ?<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p># n; U& I2 d6 Z" x# h1 ], U
<h2 id="总结">总结</h2>
7 l6 z! h8 {8 h8 J5 O0 E<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>
" q4 T* s: E$ W% a: e' i! j/ j<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>) B" w, c) ]7 z1 m* p
* X9 n9 G1 E8 n4 g6 `" [: W9 O
|
|