{"id":21328420,"url":"https://github.com/wiredviews/xperience-query-extensions","last_synced_at":"2026-03-09T13:45:01.919Z","repository":{"id":42202975,"uuid":"321136282","full_name":"wiredviews/xperience-query-extensions","owner":"wiredviews","description":"This package provides helpful extension methods for the various Kentico Xperience Document/Object query APIs.","archived":false,"fork":false,"pushed_at":"2023-01-26T19:02:19.000Z","size":127,"stargazers_count":2,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-28T03:39:18.305Z","etag":null,"topics":["cms","dotnet","kentico-xperience"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wiredviews.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-13T18:50:08.000Z","updated_at":"2024-10-11T14:17:34.000Z","dependencies_parsed_at":"2023-02-14T21:40:50.751Z","dependency_job_id":null,"html_url":"https://github.com/wiredviews/xperience-query-extensions","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/wiredviews/xperience-query-extensions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiredviews%2Fxperience-query-extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiredviews%2Fxperience-query-extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiredviews%2Fxperience-query-extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiredviews%2Fxperience-query-extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wiredviews","download_url":"https://codeload.github.com/wiredviews/xperience-query-extensions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wiredviews%2Fxperience-query-extensions/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264958135,"owners_count":23689006,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","dotnet","kentico-xperience"],"created_at":"2024-11-21T21:28:52.979Z","updated_at":"2026-03-09T13:45:01.855Z","avatar_url":"https://github.com/wiredviews.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Xperience Query Extensions\n\n[![GitHub Actions CI: Build](https://github.com/wiredviews/xperience-query-extensions/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/wiredviews/xperience-query-extensions/actions/workflows/ci.yml)\n\n[![Publish Packages to NuGet](https://github.com/wiredviews/xperience-query-extensions/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/wiredviews/xperience-query-extensions/actions/workflows/publish.yml)\n\n[![NuGet Package](https://img.shields.io/nuget/v/XperienceCommunity.QueryExtensions.svg)](https://www.nuget.org/packages/XperienceCommunity.QueryExtensions)\n\nThis package provides a set of extension methods for Kentico Xperience 13.0 `DocumentQuery`, `MultiDocumentQuery`, `ObjectQuery`, and `IPageRetriever` [data access APIs](https://docs.xperience.io/13api/content-management/pages).\n\n## Dependencies\n\nThis package is compatible with ASP.NET Core 3.1 -\u003e ASP.NET Core 5 applications or libraries integrated with Kentico Xperience 13.0.\n\n## How to Use?\n\n1. Install the NuGet package in your ASP.NET Core project (or class library)\n\n   ```bash\n   dotnet add package XperienceCommunity.QueryExtensions\n   ```\n\n1. Add the correct `using` to have the extensions appear in intellisense\n\n   `using XperienceCommunity.QueryExtensions.Documents;`\n\n   `using XperienceCommunity.QueryExtensions.Objects;`\n\n   `using XperienceCommunity.QueryExtensions.Collections;`\n\n   \u003e The extension methods are all in explicit namespaces to prevent conflicts with extensions that Xperience might add in the future or extensions that the developer might have already created.\n   \u003e\n   \u003e If you are using C# 10, you can apply these globally with [C# 10 implicit usings](https://docs.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives)\n\n## Extension Methods\n\n### DocumentQuery\n\n#### Prerequisites\n\n```csharp\nusing XperienceCommunity.QueryExtensions.Documents;\n```\n\n#### Examples\n\n\u003e These work for both `DocumentQuery\u003cT\u003e` and `MultiDocumentQuery`\n\n```csharp\npublic void QueryDocument(Guid nodeGuid)\n{\n    var query = DocumentHelper.GetDocuments()\n        .WhereNodeGUIDEquals(nodeGuid);\n}\n```\n\n```csharp\npublic void QueryDocument(int nodeID)\n{\n    var query = DocumentHelper.GetDocuments()\n        .WhereNodeIDEquals(nodeID);\n}\n```\n\n```csharp\npublic void QueryDocument(int documentID)\n{\n    var query = DocumentHelper.GetDocuments()\n        .WhereDocumentIDEquals(documentID);\n}\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .OrderByNodeOrder();\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .Tap(q =\u003e \n    {\n        // access the query 'q'\n    });\n```\n\n```csharp\nbool condition = ...\n\nvar query = DocumentHelper.GetDocuments()\n    .If(condition, q =\u003e \n    {\n        // when condition is true\n    });\n```\n\n```csharp\nbool condition = ...\n\nvar query = DocumentHelper.GetDocuments()\n    .If(condition, \n    q =\u003e \n    {\n        // when condition is true\n    }, \n    q =\u003e\n    {\n        // when condition is false\n    });\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .OrderByDescending(nameof(TreeNode.NodeID))\n    .TopN(1)\n    .DebugQuery();\n\n/*\n--- BEGIN [path\\to\\your\\app\\Program.cs] QUERY ---\n\n\nDECLARE @DocumentCulture nvarchar(max) = N'en-US';\n\nSELECT TOP 1 *\nFROM View_CMS_Tree_Joined AS V WITH (NOLOCK, NOEXPAND) LEFT OUTER JOIN COM_SKU AS S WITH (NOLOCK) ON [V].[NodeSKUID] = [S].[SKUID]\nWHERE [DocumentCulture] = @DocumentCulture\nORDER BY NodeID DESC\n\n\n--- END [path\\to\\your\\app\\Program.cs] QUERY ---\n*/\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .OrderByDescending(nameof(TreeNode.NodeID))\n    .TopN(1)\n    .DebugQuery(\"Newest Document\");\n\n/*\n--- BEGIN [Newest Document] QUERY ---\n\n\nDECLARE @DocumentCulture nvarchar(max) = N'en-US';\n\nSELECT TOP 1 *\nFROM View_CMS_Tree_Joined AS V WITH (NOLOCK, NOEXPAND) LEFT OUTER JOIN COM_SKU AS S WITH (NOLOCK) ON [V].[NodeSKUID] = [S].[SKUID]\nWHERE [DocumentCulture] = @DocumentCulture\nORDER BY NodeID DESC\n\n\n--- END [Newest Document] QUERY ---\n*/\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .OrderByDescending(nameof(TreeNode.NodeID))\n    .TopN(1)\n    .TapQueryText(fullQueryText =\u003e\n    {\n        Debug.WriteLine(fullQueryText);\n    })\n    .WhereEquals(...)\n```\n\n```csharp\npublic void QueryDatabase(ILogger logger)\n{\n    var query = DocumentHelper.GetDocuments()\n        .OrderByDescending(nameof(TreeNode.NodeID))\n        .TopN(1)\n        .LogQuery(logger, \"Logged Query\");\n}\n```\n\n```csharp\nvar query = DocumentHelper.GetDocuments()\n    .Where(w =\u003e w.WhereInPath(\"path1\", \"path2\"));\n```\n\n### ObjectQuery\n\n#### Prerequisites\n\n```csharp\nusing XperienceCommunity.QueryExtensions.Objects;\n```\n\n#### Examples\n\n```csharp\nreturn UserInfo.Provider.Get()\n    .Tap(q =\u003e\n    {\n        // access the query\n    });\n```\n\n```csharp\nbool condition = ...\n\nvar query = UserInfo.Provider.Get()\n    .If(condition, q =\u003e \n    {\n        // when condition is true\n    });\n```\n\n```csharp\nbool condition = ...\n\nvar query = UserInfo.Provider.Get()\n    .If(condition, \n    q =\u003e \n    {\n        // when condition is true\n    }, \n    q =\u003e\n    {\n        // when condition is false\n    });\n```\n\n```csharp\nvar query = UserInfo.Provider.Get()\n    .OrderByDescending(nameof(UserInfo.UserLastModified))\n    .TopN(1)\n    .DebugQuery();\n\n/*\n--- BEGIN [path\\to\\your\\app\\Program.cs] QUERY ---\n\n\nSELECT TOP 1 *\nFROM CMS_User\nORDER BY UserLastModified DESC\n\n\n--- END [path\\to\\your\\app\\Program.cs] QUERY ---\n*/\n```\n\n```csharp\nvar query = UserInfo.Provider.Get()\n    .OrderByDescending(nameof(UserInfo.UserLastModified))\n    .TopN(1)\n    .DebugQuery(\"User\");\n\n/*\n--- QUERY [User] START ---\n\n\nSELECT TOP 1 *\nFROM CMS_User\nORDER BY UserLastModified DESC\n\n\n--- QUERY [User] END ---\n*/\n```\n\n```csharp\npublic void QueryDatabase(ILogger logger)\n{\n    var query = UserInfo.Provider.Get()\n        .OrderByDescending(nameof(UserInfo.UserLastModified))\n        .TopN(1)\n        .LogQuery(logger, \"Logged User Query\");\n}\n```\n\n```csharp\nvar query = UserInfo.Provider.Get()\n    .TapQueryText(text =\u003e\n    {\n        // do something with the query text\n    });\n```\n\n```csharp\nvar query = UserInfo.Provider.Get()\n    .Source(s =\u003e s.InnerJoin\u003cUserSettingInfo\u003e(\n        \"UserID\", \n        \"UserSettingUserID\", \n        \"MY_ALIAS\",\n        additionalCondition: new WhereCondition(\"MY_ALIAS.UserWaitingForApproval\", QueryOperator.Equals, true),\n        hints: new[] { SqlHints.NOLOCK }))\n    .TopN(1)\n    .DebugQuery(\"User\");\n\n/*\n--- QUERY [User] START ---\n\n\nSELECT TOP 1 *\nFROM CMS_User\nINNER JOIN CMS_UserSetting AS MY_ALIAS WITH (NOLOCK) ON UserID = MY_ALIAS.UserSettingUserID AND MY_ALIAS.UserWaitingForApproval = 1\nORDER BY UserLastModified DESC\n\n\n--- QUERY [User] END ---\n*/\n```\n\n```csharp\n// ExecuteAsync returns a populated dataset with all the columns returned by the query.\n// When there are no results, dataset.Tables[0] will still be populated with an empty DataTable.\n\nvar dataset = await UserInfo.Provider.Get()\n    .Source(source =\u003e source\n        .InnerJoin\u003cUserSettingInfo\u003e(\n            \"UserID\", \n            \"UserSettingUserID\", \n            \"MY_ALIAS\")\n        .InnerJoin\u003cCustomerInfo\u003e(\n            \"CustomerUserID\",\n            \"UserID\",\n            \"C\",\n            )\n        )\n    .Columns(\"UserID\", \"UserSettingID\", \"CustomerID\")\n    .ExecuteAsync();\n    \nforeach (var row in dataset.Tables[0].Rows)\n{\n    Console.WriteLine($\"User: {row[\"UserID\"]}, User Setting: {row[\"UserSettingID\"]}, Customer: {row[\"CustomerID\"]}\");\n}\n```\n\n### Collections\n\n#### Requirements\n\n```csharp\nusing XperienceCommunity.QueryExtensions.Collections;\n```\n\n#### Examples\n\n```csharp\nTreeNode? page = await retriever\n    .RetrieveAsync\u003cTreeNode\u003e(q =\u003e q.TopN(1), cancellationToken: token)\n    .FirstOrDefaultAsync();\n```\n\n```csharp\nIList\u003cTreeNode\u003e pages = await retriever\n    .RetrieveAsync\u003cTreeNode\u003e(cancellationToken: token)\n    .ToListAsync();\n```\n\n```csharp\nIList\u003cTreeNode\u003e pages = await retriever\n    .RetrieveAsync\u003cTreeNode\u003e(cancellationToken: token)\n    .ToArrayAsync();\n```\n\n### PageRetriever\n\n#### Requirements\n\n```csharp\nusing Kentico.Content.Web.Mvc;\n```\n\n#### Examples\n\n```csharp\nvoid GetPages(int pageIndex, int pageSize)\n{\n    var result = await retriever.RetrievePagedAsync\u003cTreeNode\u003e(\n        pageIndex,\n        pageSize,\n        q =\u003e q.OrderByNodeOrder(),\n        cancellationToken: token);\n\n    int total = result.TotalRecords;\n    List\u003cTreeNode\u003e pages = result.Items;\n\n    // or\n\n    var (totalRecords, pages) = await retriever.RetrievePagedAsync\u003cTreeNode\u003e(\n        pageIndex,\n        pageSize,\n        q =\u003e q.OrderByNodeOrder(),\n        cancellationToken: token);\n}\n```\n\n### XperienceCommunityConnectionHelper\n\n#### Examples\n\n```csharp\nvar dataSet = await XperienceCommunityConnectionHelper.ExecuteQueryAsync(\"CMS.User\", \"GetAllUsersCustom\");\n```\n\n```csharp\nstring queryText = @\"\nSELECT *\nFROM CMS_User\nWHERE UserID = @UserID\n\"\n\nvar queryParams = new QueryDataParameters\n{\n    { \"UserID\", 3 }\n};\n\nvar dataSet = await XperienceCommunityConnectionHelper.ExecuteQueryAsync(queryText, queryParams, token: token);\n```\n\n## References\n\n### .NET\n\n- [Nullable reference types (C# reference)](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types)\n\n### Kentico Xperience\n\n- [Kentico Xperience 13 Beta 3 - New Data Access APIs](https://dev.to/seangwright/kentico-xperience-13-beta-3-new-data-access-apis-1oha)\n- [Pages API Examples](https://docs.xperience.io/13api/content-management/pages)\n- [Retrieving pages in custom scenarios](https://docs.xperience.io/custom-development/working-with-pages-in-the-api#WorkingwithpagesintheAPI-Retrievingpagesincustomscenarios)\n- [Improvements under the hood – Document and ObjectQuery enumeration without DataSets](https://devnet.kentico.com/articles/improvements-under-the-hood-document-and-objectquery-enumeration-without-datasets)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwiredviews%2Fxperience-query-extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwiredviews%2Fxperience-query-extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwiredviews%2Fxperience-query-extensions/lists"}