Skip to content

Commit dc8f611

Browse files
author
github-actions
committed
Documentation update
1 parent 3500198 commit dc8f611

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

docs/guides/dataloader/index.html

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ <h2 id="setup" style="position:relative;"><a href="#setup" aria-label="setup per
102102
<h2 id="usage" style="position:relative;"><a href="#usage" aria-label="usage permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Usage</h2>
103103
<p>First, inject the <code class="language-text">IDataLoaderContextAccessor</code> into your GraphQL type class.</p>
104104
<p>Then use the <code class="language-text">Context</code> property on the accessor to get the current <code class="language-text">DataLoaderContext</code>. The <code class="language-text">DataLoaderDocumentListener</code> configured above ensures that each request will have its own context instance.</p>
105-
<p>Use one of the "GetOrAddLoader" methods on the <code class="language-text">DataLoaderContext</code>. These methods all require a string key to uniquely identify each loader. They also require a delegate for fetching the data. Each method will get an existing loader or add a new one, identified by the string key. Each method has various overloads to support different ways to load and map data with the keys.</p>
105+
<p>Use one of the <code class="language-text">GetOrAdd*Loader</code> methods on the <code class="language-text">DataLoaderContext</code>. These methods all require a string key to uniquely identify each loader. They also require a delegate for fetching the data. Each method will get an existing loader or add a new one, identified by the string key. Each method has various overloads to support different ways to load and map data with the keys.</p>
106106
<p>Call <code class="language-text">LoadAsync()</code> on the data loader. This will queue the request and return a <code class="language-text">IDataLoaderResult&lt;T></code>. If the result has already been cached, the returned value will be pulled from the cache.</p>
107107
<p>The <code class="language-text">ExecutionStrategy</code> will dispatch queued data loaders after all other pending fields have been resolved.</p>
108108
<p>If your code requires an asynchronous call prior to queuing the data loader, use the <code class="language-text">ResolveAsync</code> field builder method to return a
@@ -113,8 +113,26 @@ <h2 id="usage" style="position:relative;"><a href="#usage" aria-label="usage per
113113
method of the returned <code class="language-text">IDataLoaderResult&lt;T></code>. You can use a synchronous or asynchronous delegate, and it can return another
114114
<code class="language-text">IDataLoaderResult&lt;T></code> if you wish to chain dataloaders together. This may result in the field builder's Resolve delegate
115115
signature looking like <code class="language-text">IDataLoaderResult&lt;IDataLoaderResult&lt;T>></code>, which is correct and will be handled properly by the execution strategy.</p>
116+
<h3 id="getoraddbatchloader-vs-getoraddcollectionbatchloader" style="position:relative;"><a href="#getoraddbatchloader-vs-getoraddcollectionbatchloader" aria-label="getoraddbatchloader vs getoraddcollectionbatchloader permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>GetOrAddBatchLoader vs. GetOrAddCollectionBatchLoader</h3>
117+
<p>The decision about whether to use the <code class="language-text">GetOrAddBatchLoader</code> or <code class="language-text">GetOrAddCollectionBatchLoader</code> method should be based on whether each key can link to only one or to multiple values:</p>
118+
<ul>
119+
<li>use <code class="language-text">GetOrAddBatchLoader</code> for one-to-one or many-to-one relationships, i.e. when each key links to a single value; think for example of resolving the user who made an order: each order maps to one (and only one) user;</li>
120+
<li>use <code class="language-text">GetOrAddCollectionBatchLoader</code> for one-to-many or many-to-many relationships, i.e. when each key links to multiple values; think for example of resolving orders for a user: each user may map to (zero or) more orders.</li>
121+
</ul>
122+
<p>Note that what matters here is the cardinality of the relation as seen from the resolver's perspective. Think for example of orders and products. In theory, a product can appear in multiple orders and an order can contain multiple products, so this is a many-to-many relationship. However, a resolver for <code class="language-text">Product.Orders</code> (or alternatively, <code class="language-text">Order.Products</code>) will only need to care for the one-to-many side of the relation, and thus use the <code class="language-text">GetOrAddBatchCollectionLoader</code>.</p>
123+
<p>The same applies to one-to-many (or many-to-one) relationships. A resolver on the "one" side of the relation will need to use <code class="language-text">GetOrAddBatchCollectionLoader</code>, while a resolver on the "many" side will need to use <code class="language-text">GetOrAddBatchLoader</code>.</p>
116124
<h2 id="examples" style="position:relative;"><a href="#examples" aria-label="examples permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Examples</h2>
117-
<p>This is an example of using a DataLoader to batch requests for loading items by a key. <code class="language-text">LoadAsync()</code> is called by the field resolver for each Order. <code class="language-text">IUsersStore.GetUsersByIdAsync()</code> will be called with the batch of userIds that were requested.</p>
125+
<p>Below are some example implementations of a DataLoader for different use cases given the following schema:</p>
126+
<div class="gatsby-highlight" data-language="graphql"><pre class="language-graphql"><code class="language-graphql"><span class="token keyword">type</span> <span class="token class-name">Order</span> <span class="token punctuation">{</span>
127+
<span class="token attr-name">User</span><span class="token punctuation">:</span> <span class="token class-name">User</span><span class="token operator">!</span> <span class="token comment"># many-to-one</span>
128+
<span class="token punctuation">}</span>
129+
130+
<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
131+
<span class="token attr-name">Orders</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Order</span><span class="token operator">!</span><span class="token punctuation">]</span><span class="token operator">!</span> <span class="token comment"># one-to-many</span>
132+
<span class="token punctuation">}</span></code></pre></div>
133+
<h3 id="one-to-one-or-many-to-one-relationships-code-classlanguage-textorderusercode" style="position:relative;"><a href="#one-to-one-or-many-to-one-relationships-code-classlanguage-textorderusercode" aria-label="one to one or many to one relationships code classlanguage textorderusercode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>One-to-one or many-to-one relationships (<code class="language-text">Order.User</code>)</h3>
134+
<p>This is an example of using a DataLoader to batch requests for loading a single item by a key. Since each order belongs to exactly one user, from the perspective of an order this is a one-to-one relationship, so we should use <code class="language-text">GetOrAddBatchLoader</code>.</p>
135+
<p>Below, <code class="language-text">LoadAsync()</code> is called by the field resolver for each Order. <code class="language-text">IUsersStore.GetUsersByIdAsync()</code> will be called with the batch of userIds that were requested.</p>
118136
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">OrderType</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ObjectGraphType<span class="token punctuation">&lt;</span>Order<span class="token punctuation">></span></span></span>
119137
<span class="token punctuation">{</span>
120138
<span class="token comment">// Inject the IDataLoaderContextAccessor to access the current DataLoaderContext</span>
@@ -139,13 +157,21 @@ <h2 id="examples" style="position:relative;"><a href="#examples" aria-label="exa
139157
<span class="token punctuation">}</span>
140158
<span class="token punctuation">}</span>
141159

142-
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">IUsersStore</span>
160+
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserStore</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IUsersStore</span></span>
143161
<span class="token punctuation">{</span>
144162
<span class="token comment">// This will be called by the loader for all pending keys</span>
145163
<span class="token comment">// Note that fetch delegates can accept a CancellationToken parameter or not</span>
146-
<span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>IDictionary<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> User<span class="token punctuation">></span><span class="token punctuation">></span></span> <span class="token function">GetUsersByIdAsync</span><span class="token punctuation">(</span><span class="token class-name">IEnumerable<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">></span></span> userIds<span class="token punctuation">,</span> <span class="token class-name">CancellationToken</span> cancellationToken<span class="token punctuation">)</span><span class="token punctuation">;</span>
164+
<span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>IDictionary<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">,</span> User<span class="token punctuation">></span><span class="token punctuation">></span></span> <span class="token function">GetUsersByIdAsync</span><span class="token punctuation">(</span><span class="token class-name">IEnumerable<span class="token punctuation">&lt;</span><span class="token keyword">int</span><span class="token punctuation">></span></span> userIds<span class="token punctuation">,</span> <span class="token class-name">CancellationToken</span> cancellationToken<span class="token punctuation">)</span>
165+
<span class="token punctuation">{</span>
166+
<span class="token class-name"><span class="token keyword">var</span></span> users <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token range operator">..</span><span class="token punctuation">.</span> <span class="token comment">// load data from database</span>
167+
168+
<span class="token keyword">return</span> users
169+
<span class="token punctuation">.</span><span class="token function">ToDictionary</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>UserId<span class="token punctuation">)</span><span class="token punctuation">;</span>
170+
<span class="token punctuation">}</span>
147171
<span class="token punctuation">}</span></code></pre></div>
148-
<p>This is an example of using a DataLoader to batch requests for loading a collection of items by a key. This is used when a key may be associated with more than one item. <code class="language-text">LoadAsync()</code> is called by the field resolver for each User. A User can have zero to many Orders. <code class="language-text">IOrdersStore.GetOrdersByUserIdAsync</code> will be called with a batch of userIds that have been requested.</p>
172+
<h3 id="one-to-many-or-many-to-many-relationships-code-classlanguage-textuserorderscode" style="position:relative;"><a href="#one-to-many-or-many-to-many-relationships-code-classlanguage-textuserorderscode" aria-label="one to many or many to many relationships code classlanguage textuserorderscode permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>One-to-many or many-to-many relationships (<code class="language-text">User.Orders</code>)</h3>
173+
<p>This is an example of using a DataLoader to batch requests for loading a collection of items by a key. This is used when a key may be associated with more than one item. Since each user can have (zero or) more orders, from the perspective of a user this is a one-to-many relationship, so we should use <code class="language-text">GetOrAddCollectionBatchLoader</code>.</p>
174+
<p><code class="language-text">LoadAsync()</code> is called by the field resolver for each User. <code class="language-text">IOrdersStore.GetOrdersByUserIdAsync</code> will be called with a batch of userIds that have been requested.</p>
149175
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserType</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ObjectGraphType<span class="token punctuation">&lt;</span>User<span class="token punctuation">></span></span></span>
150176
<span class="token punctuation">{</span>
151177
<span class="token comment">// Inject the IDataLoaderContextAccessor to access the current DataLoaderContext</span>
@@ -182,6 +208,7 @@ <h2 id="examples" style="position:relative;"><a href="#examples" aria-label="exa
182208
<span class="token punctuation">}</span>
183209
<span class="token punctuation">}</span>
184210
</code></pre></div>
211+
<h3 id="no-batching" style="position:relative;"><a href="#no-batching" aria-label="no batching permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>No batching</h3>
185212
<p>This is an example of using a DataLoader without batching. This could be useful if the data may be requested multiple times. The result will be cached the first time. Subsequent calls to <code class="language-text">LoadAsync()</code> will return the cached result.</p>
186213
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">QueryType</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ObjectGraphType</span></span>
187214
<span class="token punctuation">{</span>
@@ -208,6 +235,7 @@ <h2 id="examples" style="position:relative;"><a href="#examples" aria-label="exa
208235
<span class="token punctuation">{</span>
209236
<span class="token return-type class-name">Task<span class="token punctuation">&lt;</span>IEnumerable<span class="token punctuation">&lt;</span>User<span class="token punctuation">></span><span class="token punctuation">></span></span> <span class="token function">GetAllUsersAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
210237
<span class="token punctuation">}</span></code></pre></div>
238+
<h3 id="chained-data-loaders" style="position:relative;"><a href="#chained-data-loaders" aria-label="chained data loaders permalink" class="anchor before"><svg aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Chained data loaders</h3>
211239
<p>This is an example of using two chained DataLoaders to batch requests together, with asynchronous code before the data loaders execute, and post-processing afterwards.</p>
212240
<div class="gatsby-highlight" data-language="csharp"><pre class="language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserType</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">ObjectGraphType<span class="token punctuation">&lt;</span>User<span class="token punctuation">></span></span></span>
213241
<span class="token punctuation">{</span>

page-data/docs/guides/dataloader/page-data.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)