From b4c18d0f9da6cf23fe42c5d8c8e1659ff24718eb Mon Sep 17 00:00:00 2001 From: Mihail Date: Fri, 20 Feb 2026 15:23:14 +0100 Subject: [PATCH 1/2] refactor: add optional include=* query parameter --- Dappi.SourceGenerator/CrudGenerator.cs | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Dappi.SourceGenerator/CrudGenerator.cs b/Dappi.SourceGenerator/CrudGenerator.cs index fff6139..fbe45c2 100644 --- a/Dappi.SourceGenerator/CrudGenerator.cs +++ b/Dappi.SourceGenerator/CrudGenerator.cs @@ -151,6 +151,21 @@ private dynamic GetDbSetForType(string typeName) private IQueryable<{item.ClassName}> ApplyDynamicIncludes(IQueryable<{item.ClassName}> query) {{ + if (!HttpContext.Request.Query.ContainsKey(""include"")) + {{ + return query; + }} + + var shouldApplyFullIncludes = HttpContext.Request.Query[""include""] + .SelectMany(includeValue => includeValue + .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) + .Any(includePath => includePath == ""*""); + + if (shouldApplyFullIncludes) + {{ + return ApplyFullIncludes(query); + }} + var includeTree = HttpContext.Items[IncludeQueryFilter.IncludeParamsKey] as IDictionary; if (includeTree is null || includeTree.Count == 0) {{ @@ -165,6 +180,54 @@ private dynamic GetDbSetForType(string typeName) return query; }} +private IQueryable<{item.ClassName}> ApplyFullIncludes(IQueryable<{item.ClassName}> query) + {{ + var rootEntityType = dbContext.Model.FindEntityType(typeof({item.ClassName})); + if (rootEntityType is null) + {{ + return query; + }} + + var includePaths = new HashSet(StringComparer.OrdinalIgnoreCase); + var visitedTypes = new HashSet(StringComparer.OrdinalIgnoreCase); + visitedTypes.Add(rootEntityType.Name); + var prefix = string.Empty; + + CollectIncludePaths(rootEntityType, prefix, includePaths, visitedTypes); + + foreach (var includePath in includePaths) + {{ + query = query.Include(includePath); + }} + + return query; + }} + + private static void CollectIncludePaths( + Microsoft.EntityFrameworkCore.Metadata.IEntityType entityType, + string prefix, + HashSet includePaths, + HashSet visitedTypes) + {{ + var relations = entityType.GetNavigations(); + foreach (var relation in relations) + {{ + var entityTypeName = relation.TargetEntityType.Name; + if (visitedTypes.Contains(entityTypeName)) + {{ + continue; + }} + + var navigationPath = string.IsNullOrEmpty(prefix) ? relation.Name : string.Concat(prefix, ""."", relation.Name); + + includePaths.Add(navigationPath); + visitedTypes.Add(entityTypeName); + + CollectIncludePaths(relation.TargetEntityType, navigationPath, includePaths, visitedTypes); + visitedTypes.Remove(entityTypeName); + }} + }} + private static IQueryable<{item.ClassName}> ApplyIncludeRecursively(IQueryable<{item.ClassName}> query, string path, IncludeNode node) {{ query = query.Include(path); From 4bfe8d36f890a14f14a5c47768c740ce04783cb4 Mon Sep 17 00:00:00 2001 From: Mihail Date: Fri, 20 Feb 2026 15:30:17 +0100 Subject: [PATCH 2/2] refactor: remove TestController --- .../MyCompany.MyProject.WebApi/Controllers/TestController.cs | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs diff --git a/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs b/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs deleted file mode 100644 index ef87d91..0000000 --- a/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MyCompany.MyProject.WebApi.Controllers; - -public class TestController { }