diff --git a/CCUI.DAPPI/src/app/state/content/content.effects.ts b/CCUI.DAPPI/src/app/state/content/content.effects.ts index 53a86554..cccf51ba 100644 --- a/CCUI.DAPPI/src/app/state/content/content.effects.ts +++ b/CCUI.DAPPI/src/app/state/content/content.effects.ts @@ -38,6 +38,7 @@ export class ContentEffects { offset: ((action.page - 1) * action.limit).toString(), limit: action.limit.toString(), SearchTerm: action.searchText || '', + include: '*', }, }) .pipe( diff --git a/Dappi.SourceGenerator/CrudGenerator.cs b/Dappi.SourceGenerator/CrudGenerator.cs index fff6139f..81dfb185 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 ?? string.Empty) + .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); diff --git a/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs b/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs deleted file mode 100644 index ef87d912..00000000 --- a/templates/MyCompany.MyProject.WebApi/Controllers/TestController.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace MyCompany.MyProject.WebApi.Controllers; - -public class TestController { }