{"id":233,"date":"2014-07-09T00:09:00","date_gmt":"2014-07-09T00:09:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2014\/07\/09\/tutorial-sample-client-delayed-query\/"},"modified":"2020-01-07T07:18:13","modified_gmt":"2020-01-07T14:18:13","slug":"tutorial-sample-client-delayed-query","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/tutorial-sample-client-delayed-query\/","title":{"rendered":"[Tutorial &amp; Sample] Client Delayed Query"},"content":{"rendered":"<p>In OData Client 6.5.0, together with OData Client Code Generator 2.0.0, we have improved the user experience on the client side by introducing delayed query into it. This feature enables valid compositions as many as you want when building a query in client, getting all parts into one request URL and sending it out when you get it ready.<\/p>\n<p>Currently, we support the generation of all operation imports and operations bound on single entity or a collection of entities in OData Client Code Generator 2.0.0, so as to invoke them directly in C# or VB .NET when writing client code to build queries. Bound functions can be used in query options such as \u201c$filter\u201d or \u201c$orderby\u201d too. Operations bound to other resources (e.g. primitive types, complex types, etc.) are not supported yet. Neither are unbound operations exclusive of operation imports.<\/p>\n<p>Basically, we aligned with the previous code experience in OData client, but there\u2019re still some minor changes have been made to differentiate a single entity and a collection of entities when building queries. Plus, some new features together with new code patterns will be introduced here.<\/p>\n<p><span style=\"font-size: small;\"><strong>Hints at the beginning:<\/strong><\/span><\/p>\n<p>1. All samples below are based on the service EDM model <a title=\"Trip Pin Service\" href=\"https:\/\/services.odata.org\/V4\/TripPinService\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/p>\n<p>2. You can read \u201c<a title=\"How to use OData Client Code Generator to generate client-side proxy class\" href=\"http:\/\/blogs.msdn.com\/b\/odatateam\/archive\/2014\/03\/11\/how-to-use-odata-client-code-generator-to-generate-client-side-proxy-class.aspx\" target=\"_blank\" rel=\"noopener noreferrer\">How to use OData Client Code Generator to generate client-side proxy class<\/a>\u201d for generating client side proxy class.<\/p>\n<p>Now, let\u2019s start!<\/p>\n<h2><strong style=\"color: #666699; font-size: medium;\">Query a Singleton or a Single Entity<\/strong><\/h2>\n<p>As you know, we simply treated Singletons the same as EntitySets before, which means you cannot distinguish a Singleton from an EntitySet without looking them up in the metadata document. It has been optimized by using another type generated by T4 template to represent Singletons, while EntitySets stay unchanged.<\/p>\n<p>An entity selected from a collection of entities is also represented by this new type when building queries. Use the \u201c<strong>ByKey<\/strong>\u201d method to get the specific entity by passing a dictionary as the argument into it to specify its key(s). The usages of Projection and Expand are the same as what they\u2019re on EntitySet. To retrieve the item from the server after query building is finished, call \u201c<strong>GetValue<\/strong>\u201d to send the request out and get the result back.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Query a Singleton:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/c06e68bb97ea74737f82.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Query a person whose UserName is \u201crussellwhyte\u201d:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/c8c5c4551dc8d8067dc3.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Projection and Expand:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/57fe55ae8d95d31e5e63.js\"><\/script><\/p>\n<h2><span style=\"color: #666699;\"><strong><span style=\"font-size: medium;\">Query Navigation Properties<\/span><\/strong><\/span><\/h2>\n<p>To get a navigation property, we can only use \u201cExpand\u201d on an entity before. This has extremely limited our query capability on the client side. Things have changed now. We can get only the navigation properties of an entity without \u201cExpand\u201d, and invoke operations on them conveniently.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Query a navigation property on an entity:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/260d8cc7f35358b64745.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Query a navigation property on an entity for multiple levels:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/e83ee71e52806f8be5fb.js\"><\/script><\/p>\n<h2><span style=\"font-size: medium;\"><strong><span style=\"color: #666699;\">Invoke <a title=\"Actions\" href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/os\/part1-protocol\/odata-v4.0-os-part1-protocol.html#_Toc372793744\" target=\"_blank\" rel=\"noopener noreferrer\">actions<\/a><\/span><\/strong><\/span><\/h2>\n<p>ActionImports and actions bound to an EntityType or a collection of entities are supported now. Action requests should be sent with the \u201cPOST\u201d method, with all parameters (if any) serialized into the body. Actions cannot be further composed, so they\u2019re always the termination of a query. Actions may or may not have return values. Please call \u201c<strong>GetValue<\/strong>\u201d for a single result and \u201c<strong>Execute<\/strong>\u201d or \u201c<strong>foreach<\/strong>\u201d to iterate directly for a collection results. If the action has no return values, please call \u201c<strong>Execute<\/strong>\u201d to send the request out.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke an ActionImport:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/908a74b9fccd0a22d78d.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Action bound on a collection of entities<\/strong><\/span><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Action bound on an EntityType:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/60da6f8ad1a838839a9c.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke bound Action on a retrieved entity:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/66c41e048a3783f9a1fd.js\"><\/script><\/p>\n<h2><span style=\"font-size: medium; color: #666699;\">Invoke <a title=\"Functions\" href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/os\/part1-protocol\/odata-v4.0-os-part1-protocol.html#_Toc372793740\" target=\"_blank\" rel=\"noopener noreferrer\">functions<\/a><\/span><\/h2>\n<p>FunctionImports, functions bound to an EntityType or a collection of entities are supported now. The parameters (if any) of a function will be serialized into its request URI as <a title=\"Inline Parameter Syntax\" href=\"http:\/\/docs.oasis-open.org\/odata\/odata\/v4.0\/os\/part1-protocol\/odata-v4.0-os-part1-protocol.html#_Inline_Parameter_Syntax\" target=\"_blank\" rel=\"noopener noreferrer\">inline parameters<\/a>. Functions can be composable if they\u2019re marked with the attribute \u201cIsComposable\u201d as \u201ctrue\u201d in the metadata, then they can be further composed in a query. If an uncomposable function is attached with more segments, an exception will be thrown. Functions must have return values, please call \u201c<strong>GetValue<\/strong>\u201d for single result and \u201c<strong>Execute<\/strong>\u201d or \u201c<strong>foreach<\/strong>\u201d to iterate directly for collection results.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke FunctionImport returning a single result with inline parameters:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/87294425d2752c4940e7.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Function bound on a collection of entities<\/strong><\/span><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Function bound on EntityType returning a collection result:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/b3c9e463882349f94689.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke bound Function on a retrieved entity:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/6e161dd67a81ec5b752f.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Function in query options:<\/strong><\/span><\/p>\n<p>Use \u201c<strong>GetValue<\/strong>\u201d to get the real type of a function return value under synchronous circumstances, then you can get access to its properties or whatever if you want. In Async environment, there\u2019s no \u201c<strong>GetValue<\/strong>\u201d method provided, so please substitute it with \u201c<strong>GetValueAsync().Result<\/strong>\u201d. Don\u2019t worry, neither \u201c<strong>GetValue<\/strong>\u201d nor \u201c<strong>GetValueAsync().Result<\/strong>\u201d will send the partial request out when they\u2019re using inside LINQ query expression.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Invoke Function with further composition:<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/714abd277ac9477a6e53.js\"><\/script><\/p>\n<h2><strong><span style=\"font-size: medium; color: #666699;\">Type Conversion<\/span><\/strong><\/h2>\n<p>In OData, we can add a type segment to an entity resource in order to cast it into its derived type. If you want to cast an entity, there\u2019re all <strong>\u201cCastTo<em>[DerivedType]<\/em><\/strong>\u201d methods respectively generated on it to accomplish this. If it is a collection of entities and you want to get all of the derived type from it, \u201c<strong>OfType&lt;T&gt;<\/strong>\u201d will be the best choice.<\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Add type segment to a collection<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/9ed446a050dca5e34a6f.js\"><\/script><\/p>\n<p><span style=\"font-size: small; color: #666699;\"><strong>&gt; Add type segment to an entity<\/strong><\/span><\/p>\n<p><script type=\"text\/javascript\" src=\"https:\/\/gist.github.com\/ODataTeam\/731ce2e77063b63cb1eb.js\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In OData Client 6.5.0, together with OData Client Code Generator 2.0.0, we have improved the user experience on the client side by introducing delayed query into it. This feature enables valid compositions as many as you want when building a query in client, getting all parts into one request URL and sending it out when [&hellip;]<\/p>\n","protected":false},"author":522,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[50],"class_list":["post-233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","tag-odata-client-tools"],"acf":[],"blog_post_summary":"<p>In OData Client 6.5.0, together with OData Client Code Generator 2.0.0, we have improved the user experience on the client side by introducing delayed query into it. This feature enables valid compositions as many as you want when building a query in client, getting all parts into one request URL and sending it out when [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/233","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/522"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=233"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/233\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}