|
|
0 }# J* n9 d, U
<h2 id="系列导航">系列导航</h2>
" C! y7 j! y& B j6 m2 [<p><a href="https://www.cnblogs.com/code4nothing/p/graphql-net6-0.html">使用Hot Chocolate和.NET 6构建GraphQL应用文章索引</a></p>
% t9 i% D' u5 }, L9 w5 y# b8 m( L<h2 id="需求">需求</h2>
9 M' n- X/ s. |1 E, H9 o<p>在讨论完GraphQL中的查询需求后,这篇文章我们将演示如何实现GraphQL中的数据添加任务。</p>
8 ?. _+ V _- q2 C. w1 T<h2 id="思路">思路</h2>
: }+ p5 p% w- G$ w5 R, U<p>在GraphQL中,对数据进行查询使用<code>query</code>,而对于修改数据则需要使用<code>mutation</code>,包括新增和修改数据。Hot Chocolate在使用Mutation的逻辑上和使用Query的基本一致,但是需要根据需要定义用于创建或者更新的数据对象,所以我们直接进行实现。</p>8 F, {3 R. G8 J6 ?
<h2 id="实现">实现</h2>
/ v- t6 y3 ]& z& [3 V! Y! h7 D<p>为了保持简单,我们先定义以下两个类型:</p>& t& k+ l* F# k" Q
<pre><code class="language-c#">// 定义新增Post的参数. {9 a1 l7 W) R F" H
public record AddPostInput(string Title, string Author);) G7 e6 b0 ~( J5 ^7 b, [
2 O0 n7 _) M1 }// 定义新增Post的返回对象. Y, @* k7 B' i- a5 g0 g
public record AddPostPayload(Post Post);7 a( R% {4 ]5 r: u: H7 H- @; c
</code></pre>
S# ?6 X. |, R2 J<p>新建<code>Mutation.cs</code>用来定义相关接口:</p>/ i: `" O( L" ?
<ul>
; [( u' d8 t: D8 B2 \<li><code>Mutation.cs</code></li>
% @" }) `) L# L* X5 g6 D5 r" A7 G</ul>) g* o3 c1 ^; C+ `8 J% b4 M- y
<pre><code class="language-c#">namespace PostGraphi.Api.GraphQL;
6 B# c1 n2 ?8 G& T; \8 P: K# ^' h- u1 F2 P% y7 k" d
public class Mutation
' Y* F( N0 D6 J( u; R3 l/ I{
! L# v) {. Q" _4 F' T Z( l5 Q public async Task<AddPostPayload> AddPostAsync(AddPostInput input, [Service] IRepository<Post> repository)
; e; W9 ~# f! k( I2 M {" V1 B; y4 E" }7 ^: K
return new AddPostPayload(await repository.AddAsync(new Post# v6 L% T' \, g, K, t
{
& w3 R9 u8 n1 T0 `( K6 i) u Title = input.Title,$ w6 g: `0 Q* r2 ?/ D5 l
Author = input.Author/ c' }" b; @' y9 U2 A, s1 \
}));
) `6 l7 T# T4 m$ {# P4 \- O" g3 N }
, c: c; A4 m( n Q( }}! ~: l' H: O- _$ e- N ]
5 p4 Z: S% `$ z0 }: F. P7 P2 g
</code></pre>! c5 H" r. q/ Z: Q) N6 M
<p>最后在注入服务的地方进行配置:</p>
* P" ?* _7 L# |' q( |: |+ q0 P<ul>0 C$ l0 W! C9 a+ d
<li><code>ProgramExtensions.cs</code></li>6 h$ U; K& Y$ `: F( u) v% X7 j* ^7 i3 N
</ul>
& g# w: q. H8 |0 M7 F4 r# L, n E<pre><code class="language-c#">builder.Services/ x& K1 K; o4 j! M7 ]2 z- M
.AddGraphQLServer(): b( I0 X+ L4 ~
.SetPagingOptions(new PagingOptions
" x; |7 ` q: C1 E {
$ r) s+ r; ~/ j( q MaxPageSize = 50,
0 J9 y- Z7 q& j3 ?1 H IncludeTotalCount = true) ~4 i7 {: ?& |6 ~$ B
})
* q& W4 X- ^! t .AddFiltering(): S- ~5 G L6 v$ s& c7 Y5 m3 r
.AddProjections()2 ~* _, p% Z# ~& V
.AddSorting()
# ^) t6 h3 _4 L' H- e# ]# L2 o .AddQueryType<Query>()
& `6 u* v8 J9 R- ~9 V7 a* g; }; V .AddMutationType<Mutation>()
' @: F7 a3 P/ Q9 G ?2 }; _2 }6 h .AddMutationConventions(new MutationConventionOptions) E+ G9 K5 l5 W, p* f9 s
{
! a, T! _; z! ~& @+ J! i9 `& |% \. d ApplyToAllMutations = true,
6 B _- f* v8 F& w U& Q/ A InputArgumentName = "input",7 y# \* g7 U1 _
InputTypeNamePattern = "{MutationName}Input",
- {( ]7 j0 z* b2 x7 G1 ~* I$ p PayloadTypeNamePattern = "{MutationName}Payload",' X* u- y& g0 a3 ]
PayloadErrorTypeNamePattern = "{MutationName}Error",3 W. b1 y9 A9 {$ W
PayloadErrorsFieldName = "errors"
3 d! I0 C) U9 @: _5 B' @ })0 U! a- L( ?( L3 i4 R3 Z
.AddType<PostType>();
9 E( D( S, V, u; v! y$ d) s% P</code></pre>% P" |' N3 A, ^% D
<p>这样就实现了新增Post的需求,下面我们来验证一下。</p>) y" m; r9 ]" m# b7 J* h6 w5 |
<h2 id="验证">验证</h2>- Y, S8 l5 T" S1 P' }% L
<p>启动<code>Api</code>项目,调用接口:</p>
5 x- J: v# |7 r# m: I<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104544617-1400586374.png" ></p>, b8 B& t% ~ o* a8 h6 G- x
<p>终端的日志输出如下:</p>: o- K3 a, {7 p/ V2 q% t
<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']' Y2 v: B: ^3 ~( p8 ?
INSERT INTO "Posts" ("Id", "Abstraction", "Author", "Content", "Created", "CreatedBy", "LastModified", "LastModifiedBy", "Link", "PublishedAt", "Title")
4 i+ o; R2 H. J, pVALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10);
! F4 ?; w* ?( T' G1 k+ ][10:45:15 INF] Executed endpoint 'Hot Chocolate GraphQL Pipeline'; A1 O6 u6 y+ O' g( x9 T" F
</code></pre>
" R1 H6 r: A: s& k<p>可以看到新建的Post已经存储到数据库中了,我们可以通过查询接口来获取详情:</p>
5 d7 O8 j. a# f2 B<p><img src="https://img2022.cnblogs.com/blog/2487237/202202/2487237-20220211104851825-1533915064.png" ></p>* s0 ^" i' K% w
<h2 id="总结">总结</h2>& x2 I5 a9 ?; A; s; A8 f% {
<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>4 i/ l& ~0 {5 \$ m2 W
<p>在下一篇文章中,我们通过<code>Mutation</code>对已有数据进行更新。</p>7 G* k$ |5 @4 O/ r& }2 o! g
" O9 D' k" @$ o& T$ W |
|